{ "version": "https://jsonfeed.org/version/1", "title": "Node.js", "description": "Node.js is a platform built on
Chrome's Javascript runtime for easily building fast, scalable network applications.", "home_page_url": "go/nodejs", "feed_url": "feed/nodejs.json", "icon": "https://cdn.v2ex.com/navatar/2421/fcb1/436_large.png?m=1650095204", "favicon": "https://cdn.v2ex.com/navatar/2421/fcb1/436_normal.png?m=1650095204", "items": [ { "author": { "url": "member/zurmokeeper", "name": "zurmokeeper", "avatar": "https://cdn.v2ex.com/avatar/b5c8/8aa0/326640_large.png?m=1723096312" }, "url": "t/1203159", "date_modified": "2026-04-03T03:00:02+00:00", "content_html": "

\u6c42\u95ee\u5927\u4f6c\uff0c\u6211\u7684 Node.js \u670d\u52a1 \u6b63\u5e38 \u8fde\u963f\u91cc\u4e91 Redis \u662f\u6b63\u5e38\u7684\uff0c\u4f46\u662f\u53c8\u65f6\u5019\u4f1a\u7a81\u7136\u62a5 read ECONNRESET \uff1f\u7528\u7684\u662f ioredis v5.4.1, \u770b\u4e86\u4e0b\u963f\u91cc\u4e91 redis \u7684\u8fde\u63a5\u6570 \u548c\u5e26\u5bbd\u90fd\u662f\u8fdc\u8fdc\u8fbe\u4e0d\u5230\uff0c\u6709\u53ef\u80fd\u662f\u4ec0\u4e48\u95ee\u9898\u5462\uff1f

\n", "date_published": "2026-04-02T10:24:41+00:00", "title": "Node.js \u670d\u52a1\u5927\u90e8\u5206\u65f6\u5019\u8fde\u963f\u91cc\u4e91 Redis \u662f\u6b63\u5e38\u7684\uff0c\u4f46\u662f\u53c8\u65f6\u5019\u4f1a\u7a81\u7136\u62a5 read ECONNRESET\uff1f", "id": "t/1203159" }, { "author": { "url": "member/BeijingBaby", "name": "BeijingBaby", "avatar": "https://cdn.v2ex.com/avatar/5129/e8be/40195_large.png?m=1763689815" }, "url": "t/1201488", "title": "2026 \u5e74\uff0c node \u5199\u540e\u7aef\u4f60\u7528\u7684 nestjs, fastify, honojs \u8fd8\u662f\u5176\u4ed6\uff1f", "id": "t/1201488", "date_published": "2026-03-27T01:24:14+00:00", "content_html": "" }, { "author": { "url": "member/uni", "name": "uni", "avatar": "https://cdn.v2ex.com/gravatar/dd6a4e14a4462dcc14ac5df07a8cbb63?s=73&d=retro" }, "url": "t/1201112", "date_modified": "2026-03-25T13:27:54+00:00", "content_html": "

effect-solutions \u8fd9\u4e2a\u5305\uff0c\u73b0\u5728\u6700\u65b0\u7684\u662f 0.5.2 \uff0cnpmmirror \u4e0a\u9762\u8fd8\u662f 0.4.13

\n

\"\"

\n

\u4e00\u4e2a\u955c\u50cf\u7ad9\u51fa\u8fd9\u79cd\u9519\u8bef\u5b9e\u5728\u662f\u592a\u6076\u5fc3\u4e86\uff0c\u6362\u817e\u8baf\u7684\u6e90\u4e86

\n", "date_published": "2026-03-25T12:49:58+00:00", "title": "npmmirror \u7adf\u7136\u6709\u4e9b\u5305\u6ca1\u6709\u66f4\u65b0\u5230\u6700\u65b0\u7248\u672c", "id": "t/1201112" }, { "author": { "url": "member/yagamil", "name": "yagamil", "avatar": "https://cdn.v2ex.com/gravatar/26595a3b82bcd82eee336675814ce135?s=73&d=retro" }, "url": "t/1198986", "title": "\u5927\u5bb6 typescript \u4e0b\u7528\u7684\u6700\u591a\u7684\u662f\u540e\u7aef\u6846\u67b6\u662f\u54ea\u4e2a\uff1f", "id": "t/1198986", "date_published": "2026-03-17T09:29:36+00:00", "content_html": "\u4e86\u89e3\u4e0b\u884c\u60c5\u3002 \u4e4b\u524d\u5199\u8fc7\u4e00\u9635\u5b50 hono \uff0c\u4f46\u611f\u89c9\u7b80\u5355\u4e8b\u60c5\u590d\u6742\u5316\u4e86\u3002 \u4e0d\u5982 express \u7684\u57fa\u7840\u52a0\u4e0a\u7c7b\u578b\u3002" }, { "author": { "url": "member/ylh1024", "name": "ylh1024", "avatar": "https://cdn.v2ex.com/gravatar/cfc5ef8f91a5ee8630838908a343521a?s=73&d=retro" }, "url": "t/1192291", "date_modified": "2026-02-11T10:39:09+00:00", "content_html": "

\u5f00\u6e90\u9879\u76ee\u6bcf\u6b21\u4e0b\u4e0b\u6765\u90fd\u8981\u6539\u4ee3\u7801\u53bb\u4ee3\u7406\u3002\u914d\u73af\u5883\u53d8\u91cf https_proxy \uff0cwsproxy \uff0cclash \u5168\u5c40\u90fd\u6ca1\u7528\u3002\n\u90fd\u5f97\u6539\u4ee3\u7801\u624d\u80fd\u8d70\u4ee3\u7406\u3002 \u7279\u522b\u662f ws \u7684 \u66f4\u9ebb\u70e6\uff0c\u8fd8\u8d70\u8d70 socks5 \u534f\u8bae\uff1b

\n", "date_published": "2026-02-11T09:14:56+00:00", "title": "\u6c42\u52a9\uff0c\u5927\u5bb6 node.js \u662f\u600e\u4e48\u4ee3\u7406\u7684", "id": "t/1192291" }, { "author": { "url": "member/laodao", "name": "laodao", "avatar": "https://cdn.v2ex.com/avatar/ec59/2661/58295_large.png?m=1675744117" }, "url": "t/1187915", "date_modified": "2026-01-23T18:15:40+00:00", "content_html": "", "date_published": "2026-01-23T09:20:27+00:00", "title": "ai \u65f6\u4ee3\uff0c node.js \u6210\u4e3a\u6838\u5fc3\u8bed\u8a00", "id": "t/1187915" }, { "author": { "url": "member/bronana", "name": "bronana", "avatar": "https://cdn.v2ex.com/avatar/9dc5/7b07/482865_large.png?m=1680471757" }, "url": "t/1183424", "title": "NestJS + Swagger UI\uff1a\u975e 200 \u72b6\u6001\u7801 Execute \u65f6\u8fd4\u56de\u503c\u4e0d\u663e\u793a\u95ee\u9898", "id": "t/1183424", "date_published": "2026-01-06T02:34:43+00:00", "content_html": "

nestjs + swagger ui

\n

\u70b9\u51fb try it out \u548c execute \u540e\uff0c

\n

\u597d\u50cf\u53ea\u6709 status 200 \u7684\u65f6\u5019\uff0c\u80fd\u770b\u5230\u6b63\u5e38\u7684\u8fd4\u56de\u503c\uff0c

\n

\u800c 201 \u6216\u8005\u5176\u5b83\u72b6\u6001\u7801\u5c31\u770b\u4e0d\u5230\u8fd4\u56de\u503c\u662f\u600e\u4e48\u56de\u4e8b\uff1f

\n

\u5176\u5b83\u72b6\u6001\u7801\u5c31\u663e\u793a\u7684 error: \u52a0\u4e00\u4e2a\u72b6\u6001\u7801

\n
// controller\n @Get('test1')\n test1() {\n return '111';\n }\n @Post('test2')\n test2() {\n return '222';\n }\n
\n

\"pic\"

\n" }, { "author": { "url": "member/ScottHU", "name": "ScottHU", "avatar": "https://cdn.v2ex.com/avatar/d239/f440/620639_large.png?m=1764858973" }, "url": "t/1177002", "title": "\u6df1\u5165 alova3 \u670d\u52a1\u7aef\u80fd\u529b\uff1a\u5206\u5e03\u5f0f BFF \u5c42\u5230 API \u7f51\u5173\u7684\u6700\u4f73\u5b9e\u8df5", "id": "t/1177002", "date_published": "2025-12-04T14:36:32+00:00", "content_html": "

\u53ef\u80fd\u5927\u5bb6\u5bf9 alova \u8fd8\u505c\u7559\u5728\u8f7b\u91cf\u5316\u7684\u8bf7\u6c42\u7b56\u7565\u5e93\u7684\u5c42\u9762\uff0c\u8fd9\u5f53\u7136\u662f alova2 \u7684\u6838\u5fc3\u7279\u70b9\uff0c\u6bd4\u5982\u4ee5\u4e0b\u8fd9\u6bb5

\n
const { loading, data, error } = useRequest(() => alovaInstance.Get('/xxx'))\n
\n

\u8fd9\u662f\u4e00\u6bb5 alova \u5728\u5ba2\u6237\u7aef\u4f7f\u7528\u7684\u5178\u578b\u4ee3\u7801\uff0c\u4e0d\u8fc7\u73b0\u5728 alova \u5df2\u7ecf\u66f4\u65b0\u5230 3 \u4e86\uff0c\u5f53\u7136\u8fd9\u4e9b client strategies \u4f9d\u7136\u662f\u539f\u6c41\u539f\u5473\u7684\uff0c\u4e0d\u8fc7\u5b83\u4e0d\u4ec5\u5c40\u9650\u4e8e\u5ba2\u6237\u7aef\uff0c\u800c\u662f\u5728\u670d\u52a1\u7aef\u4e5f\u53ef\u4ee5\u6e38\u5203\u6709\u4f59\u4e86\u3002

\n

\u5728 alova3 \u4e2d\u63d0\u4f9b\u4e86\u670d\u52a1\u7aef\u8bf7\u6c42\u7b56\u7565\uff08 server hooks \uff09\u548c redis \u3001file \u7b49\u670d\u52a1\u7aef\u7684\u5b58\u50a8\u9002\u914d\u5668\uff0c\u53ef\u4ee5\u8ba9\u6211\u4eec\u5f88\u65b9\u4fbf\u5730\u5728\u670d\u52a1\u7aef\u5b9e\u73b0\u5168\u94fe\u8def\u7684\u8bf7\u6c42\u548c\u8f6c\u53d1\u3002

\n

\u6211\u4eec\u5148\u6765\u770b\u4e00\u4e2a\u8bf7\u6c42\u7684\u5168\u6d41\u7a0b\uff1a

\n
\u5ba2\u6237\u7aef\uff08\u6d4f\u89c8\u5668/App \uff09\n \u2192 Node.js BFF \u5c42\uff08\u8f6c\u6362\u6570\u636e\u7b49\uff09\n \u2192 API \u7f51\u5173\uff08\u9274\u6743\u3001\u901f\u7387\u9650\u5236\u3001\u8def\u7531\u5206\u53d1\u7b49\uff09\n \u2192 \u540e\u7aef\u5fae\u670d\u52a1\n
\n

alova \u63d0\u4f9b\u7684 server hook \u548c\u5206\u5e03\u5f0f\u7684\u591a\u7ea7\u7f13\u5b58\uff0c\u53ef\u4ee5\u8ba9\u6211\u4eec\u5f88\u65b9\u4fbf\u5730\u5b9e\u73b0\u4ee5\u4e0a\u7684\u5168\u90e8\u5c42\u7ea7\u7684\u8bf7\u6c42\u5904\u7406\u3002

\n

\u5728 BFF \u5c42\u8f6c\u53d1\u5ba2\u6237\u7aef\u8bf7\u6c42

\n

\u5728 BFF \u5c42\u4e2d\u7ecf\u5e38\u9700\u8981\u8f6c\u53d1\u5ba2\u6237\u7aef\u8bf7\u6c42\u5230\u540e\u7aef\u5fae\u670d\u52a1\uff0c\u4f60\u53ef\u4ee5\u4f7f\u7528\u914d\u5408async_hooks\u8bbf\u95ee\u6bcf\u4e2a\u8bf7\u6c42\u7684\u4e0a\u4e0b\u6587\uff0c\u5e76\u5728 alova \u7684beforeRequest\u4e2d\u6dfb\u52a0\u5230\u8bf7\u6c42\u4e2d\uff0c\u5b9e\u73b0\u7528\u6237\u76f8\u5173\u6570\u636e\u7684\u8f6c\u53d1\u3002

\n
import { createAlova } from 'alova';\nimport adapterFetch from '@alova/fetch';\nimport express from 'express';\nimport { AsyncLocalStorage } from 'node:async_hooks';\n\n// \u521b\u5efa\u5f02\u6b65\u672c\u5730\u5b58\u50a8\u5b9e\u4f8b\nconst asyncLocalStorage = new AsyncLocalStorage();\n\nconst alovaInstance = createAlova({\n requestAdapter: adapterFetch(),\n beforeRequest(method) {\n // \u4ece\u5f02\u6b65\u4e0a\u4e0b\u6587\u4e2d\u83b7\u53d6\u8bf7\u6c42\u5934\u5e76\u4f20\u9012\u5230\u4e0b\u6e38\n const cOntext= asyncLocalStorage.getStore();\n if (context && context.headers) {\n method.config.headers = {\n ...method.config.headers,\n ...context.headers\n };\n }\n },\n responded: {\n onSuccess(response) {\n // \u6570\u636e\u8f6c\u6362\u5904\u7406\n return {\n data: response.data,\n timestamp: Date.now(),\n transformed: true\n };\n },\n onError(error) {\n console.error('Request failed:', error);\n throw error;\n }\n }\n});\n\nconst app = express();\n\n// \u4e2d\u95f4\u4ef6\u91cc\u8bbe\u7f6e\u4e00\u6b21\uff0c\u5168\u7a0b\u81ea\u52a8\u4f20\u9012\napp.use((req, res, next) => {\n const cOntext= {\n userId: req.headers['x-user-id'],\n token: req.headers['authorization']\n };\n asyncLocalStorage.run(context, next);\n});\n\n// \u4e1a\u52a1\u4ee3\u7801\u4e13\u6ce8\u4e1a\u52a1\u903b\u8f91\napp.get('/api/user-profile', async (req, res) => {\n // \u4e0d\u7528\u624b\u52a8\u4f20\u9012\u4e0a\u4e0b\u6587\u4e86\uff01\n const [userInfo, orders] = await Promise.all([\n alovaInstance.Get('http://gateway.com/user/profile'),\n alovaInstance.Get('http://gateway.com/order/recent')\n ]);\n \n res.json({ user: userInfo.data, orders: orders.data });\n});\n
\n

API \u7f51\u5173\u4e2d\u7684\u4f7f\u7528\u573a\u666f

\n

\u5728\u7f51\u5173\u4e2d\u7ecf\u5e38\u9700\u8981\u8fdb\u884c\u9274\u6743\u3001\u8bf7\u6c42\u901f\u7387\u9650\u5236\u4ee5\u53ca\u8bf7\u6c42\u5206\u53d1\u7b49\uff0calova3 \u7684 redis \u5b58\u50a8\u9002\u914d\u5668\u548c rateLimiter \u53ef\u4ee5\u5f88\u597d\u5730\u5b9e\u73b0\u5206\u5e03\u5f0f\u7684\u9274\u6743\u670d\u52a1\u548c\u8bf7\u6c42\u901f\u7387\u9650\u5236\u3002

\n

\u9274\u6743\u53ef\u4ee5\u8fd9\u4e48\u641e

\n

\u5982\u679c\u9274\u6743 token \u6709\u4e00\u5b9a\u7684\u8fc7\u671f\u65f6\u95f4\uff0c\u53ef\u5728\u7f51\u5173\u4e2d\u914d\u7f6e redis \u5b58\u50a8\u9002\u914d\u5668\uff0c\u5c06 token \u5b58\u50a8\u5728 redis \u4e2d\u4fbf\u4e8e\u91cd\u590d\u4f7f\u7528\uff0c\u5bf9\u4e8e\u5355\u673a\u7684\u96c6\u7fa4\u670d\u52a1\u4e5f\u53ef\u4ee5\u4f7f\u7528@alova/storage-file\u6587\u4ef6\u5b58\u50a8\u9002\u914d\u5668\u3002

\n
import { createAlova } from 'alova';\nimport RedisStorageAdapter from '@alova/storage-redis';\nimport adapterFetch from '@alova/fetch';\nimport express from 'express';\n\nconst redisAdapter = new RedisStorageAdapter({\n host: 'localhost',\n port: '6379',\n username: 'default',\n password: 'my-top-secret',\n db: 0\n});\n\nconst gatewayAlova = createAlova({\n requestAdapter: adapterFetch(),\n async beforeRequest(method) {\n const newToken = await authRequest(method.config.headers['Authorization'], method.config.headers['UserId'])\n method.config.headers['Authorization'] = `Bearer ${newToken}`;\n }\n // \u8bbe\u7f6e 2 \u7ea7\u5b58\u50a8\u9002\u914d\u5668\n l2Cache: redisAdapter,\n // ...\n});\n\nconst authRequest = (token, userId) => gatewayAlova.Post('http://auth.com/auth/token', null, {\n // \u8bbe\u7f6e 3 \u4e2a\u5c0f\u65f6\u7684\u7f13\u5b58\uff0c\u5c06\u4fdd\u5b58\u5728 redis \u4e2d\uff0c\u518d\u6b21\u4ee5\u76f8\u540c\u53c2\u6570\u8bf7\u6c42\u4f1a\u547d\u4e2d\u7f13\u5b58\n cacheFor: {\n mode: 'restore',\n expire: 3 * 3600 * 1000\n },\n headers: {\n 'x-user-id': userId,\n 'Authorization': `Bearer ${token}`\n }\n});\n\nconst app = express();\n\n// \u5b9e\u73b0 app \u63a5\u6536\u6240\u6709\u8bf7\u6c42\uff0c\u5e76\u8f6c\u53d1\u5230 alova\n// \u6ce8\u518c\u6240\u6709 HTTP \u65b9\u6cd5\u7684\u8def\u7531\nconst methods = ['get', 'post', 'put', 'delete', 'patch', 'options', 'head'];\nmethods.forEach(method => {\n app[method]('*', async (req, res) => {\n const { method, originalUrl, headers, body, query } = req;\n\n // \u4f7f\u7528 alova \u53d1\u9001\u8bf7\u6c42\n const respOnse= await gatewayAlova.Request({\n method: method.toLowerCase(),\n url: originalUrl,\n params: query,\n data: body,\n headers\n });\n \n // \u8f6c\u53d1\u54cd\u5e94\u5934\u90e8\n for (const [key, value] of response.headers.entries()) {\n res.setHeader(key, value);\n }\n \n // \u53d1\u9001\u54cd\u5e94\u6570\u636e\n res.status(response.status).send(await response.json());\n });\n});\n\napp.listen(3000, () => {\n console.log('Gateway server started on port 3000');\n});\n
\n

\u5f53\u7136\uff0c\u5982\u679c\u9700\u8981\u6bcf\u6b21\u8bf7\u6c42\u90fd\u91cd\u65b0\u9274\u6743\uff0c\u4e5f\u53ef\u4ee5\u5728authRequest\u4e2d\u53bb\u6389cacheFor\u5173\u95ed\u7f13\u5b58\u3002

\n

\u9650\u6d41\u7b56\u7565

\n

alova \u7684 rateLimiter \u53ef\u4ee5\u5b9e\u73b0\u5206\u5e03\u5f0f\u7684\u9650\u6d41\u7b56\u7565\uff0c\u5185\u90e8\u4f7f\u7528node-rate-limiter-flexible\u5b9e\u73b0\uff0c\u6211\u4eec\u6539\u9020\u4e00\u4e0b\u5b9e\u73b0\u3002

\n
import { createRateLimiter } from 'alova/server';\n\nconst rateLimit = createRateLimiter({\n /**\n * \u70b9\u6570\u91cd\u7f6e\u7684\u65f6\u95f4\uff0c\u5355\u4f4d ms\n * @default 4000\n */\n duration: 60 * 1000,\n /**\n * duration \u5185\u53ef\u6d88\u8017\u7684\u6700\u5927\u6570\u91cf\n * @default 4\n */\n points: 4,\n /**\n * \u547d\u540d\u7a7a\u95f4\uff0c\u591a\u4e2a rateLimit \u4f7f\u7528\u76f8\u540c\u5b58\u50a8\u5668\u65f6\u53ef\u9632\u6b62\u51b2\u7a81\n */\n keyPrefix: 'user-rate-limit',\n /**\n * \u9501\u5b9a\u65f6\u957f\uff0c\u5355\u4f4d ms \uff0c\u8868\u793a\u5f53\u5230\u8fbe\u901f\u7387\u9650\u5236\u540e\uff0c\u5c06\u5ef6\u957f[blockDuration]ms \uff0c\u4f8b\u5982 1 \u5c0f\u65f6\u5185\u5bc6\u7801\u9519\u8bef 5 \u6b21\uff0c\u5219\u9501\u5b9a 24 \u5c0f\u65f6\uff0c\u8fd9\u4e2a 24 \u5c0f\u65f6\u5c31\u662f\u6b64\u53c2\u6570\n */\n blockDuration: 24 * 60 * 60 * 1000\n});\n\nconst methods = ['get', 'post', 'put', 'delete', 'patch', 'options', 'head'];\nmethods.forEach(method => {\n app[method]('*', async (req, res) => {\n const { method, originalUrl, headers, body, query } = req;\n\n // \u5728\u6b64\u4f7f\u7528 rateLimit \u5305\u88f9\u8c03\u7528\u5373\u53ef\uff0c\u5b83\u5c06\u9ed8\u8ba4\u4f7f\u7528 l2Cache \u5b58\u50a8\u9002\u914d\u5668\u4f5c\u4e3a\u63a7\u5236\u53c2\u6570\u7684\u5b58\u50a8\uff0c\u8fd9\u8fb9\u7684\u4f8b\u5b50\u4f1a\u7528 redis \u5b58\u50a8\u9002\u914d\u5668\u3002\n const method = gatewayAlova.Request({\n method: method.toLowerCase(),\n url: originalUrl,\n params: query,\n data: body,\n headers\n });\n const respOnse= await rateLimit(method, {\n key: req.ip // \u4f7f\u7528 ip \u4f5c\u4e3a\u8ffd\u8e2a key \uff0c\u9632\u6b62\u540c\u4e00 ip \u9891\u7e41\u8bf7\u6c42\n });\n \n // ...\n });\n});\n
\n

\u7b2c\u4e09\u65b9\u670d\u52a1\u96c6\u6210\uff1a\u4ee4\u724c\u81ea\u52a8\u7ef4\u62a4

\n

\u548c\u5916\u90e8 API \u6253\u4ea4\u9053\u9700\u8981 access_token \u7ba1\u7406\uff0c\u5e76\u4e14\u5f88\u591a\u7b2c\u4e09\u65b9 access_token \u5177\u6709\u8c03\u7528\u9650\u5236\uff0c\u5728\u8fd9\u91cc\u6211\u4eec\u53ef\u4ee5\u4f7f\u7528 alova3+redis \u5b58\u50a8\u9002\u914d\u5668\u6765\u5b9e\u73b0\u5206\u5e03\u5f0f\u7684 access_token \u751f\u547d\u5468\u671f\u81ea\u52a8\u7ef4\u62a4\uff0c\u5176\u4e2d redis \u7528\u4e8e access_token \u7f13\u5b58\uff0catom hook \u7528\u4e8e\u5206\u5e03\u5f0f\u66f4\u65b0 token \u7684\u539f\u5b50\u6027\u64cd\u4f5c\u3002

\n
import { createAlova, queryCache } from 'alova';\nimport RedisStorageAdapter from '@alova/storage-redis';\nimport adapterFetch from '@alova/fetch';\nimport { atomize } from 'alova/server';\n\nconst redisAdapter = new RedisStorageAdapter({\n host: 'localhost',\n port: '6379',\n username: 'default',\n password: 'my-top-secret',\n db: 0\n});\nconst thirdPartyAlova = createAlova({\n requestAdapter: adapterFetch(),\n async beforeRequest(method) {\n // \u5224\u65ad\u662f\u5426\u4e3a\u7b2c\u4e09\u65b9 API \uff0c\u5982\u679c\u662f\u7684\u8bdd\u5219\u83b7\u53d6\u4ee4\u724c\n if (method.meta?.isThirdPartyApi) {\n // \u4ee5\u539f\u5b50\u6027\u7684\u65b9\u5f0f\u83b7\u53d6\u4ee4\u724c\uff0c\u9632\u6b62\u591a\u8fdb\u7a0b\u540c\u65f6\u83b7\u53d6 token\n const accessTokenGetMethod = getAccessToken();\n let accessToken = await queryCache(accessTokenGetMethod);\n if (!accessToken) {\n // \u83b7\u53d6\u6210\u529f\u540e\u5c06\u4f1a\u7f13\u5b58\n accessToken = await atomize(accessTokenGetMethod);\n }\n method.config.params.access_token = accessToken;\n }\n },\n l2Cache: redisAdapter,\n});\n\nconst getAccessToken = () => thirdPartyAlova.Get('http://third-party.com/token', {\n params: {\n grant_type: 'client_credentials',\n client_id: process.env.THIRD_PARTY_CLIENT_ID,\n client_secret: process.env.THIRD_PARTY_CLIENT_SECRET\n },\n cacheFor: {\n mode: 'restore',\n expire: 1 * 3600 * 1000 // \u4e24\u5c0f\u65f6\u7f13\u5b58\u65f6\u95f4\n }\n});\n\nconst getThirdPartyUserInfo = userId => thirdPartyAlova.Get('http://third-party.com/user/info', {\n params: {\n userId\n },\n meta: {\n isThirdPartyApi: true\n }\n});\n
\n

\u5199\u5728\u6700\u540e

\n

\u9664\u6b64\u4ee5\u5916\uff0calova \u8fd8\u63d0\u4f9b\u4e86\u5206\u5e03\u5f0f\u7684\u9a8c\u8bc1\u7801\u53d1\u9001\u548c\u9a8c\u8bc1\u3001\u8bf7\u6c42\u91cd\u8bd5\u7b49 server hooks \uff0c\u60f3\u4e86\u89e3\u66f4\u591a\u7684\u540c\u5b66\u53ef\u4ee5\u53c2\u8003\u670d\u52a1\u7aef\u8bf7\u6c42\u7b56\u7565\u3002

\n

\u5982\u679c\u89c9\u5f97 alova \u8fd8\u4e0d\u9519\uff0c\u771f\u8bda\u5e0c\u671b\u4f60\u53ef\u4ee5\u5c1d\u8bd5\u4f53\u9a8c\u4e00\u4e0b\uff0c\u4e5f\u53ef\u4ee5\u7ed9\u6211\u4eec\u6765\u4e00\u4e2a\u514d\u8d39\u7684github stars\u3002

\n

\u8bbf\u95ee alovajs \u7684\u5b98\u7f51\u67e5\u770b\u66f4\u591a\u8be6\u7ec6\u4fe1\u606f\uff1aalovajs \u5b98\u7f51\u3002

\n

\u6709\u5174\u8da3\u53ef\u4ee5\u52a0\u5165\u6211\u4eec\u7684\u4ea4\u6d41\u793e\u533a\uff0c\u5728\u7b2c\u4e00\u65f6\u95f4\u83b7\u53d6\u5230\u6700\u65b0\u8fdb\u5c55\uff0c\u4e5f\u80fd\u76f4\u63a5\u548c\u5f00\u53d1\u56e2\u961f\u4ea4\u6d41\uff0c\u63d0\u51fa\u4f60\u7684\u60f3\u6cd5\u548c\u5efa\u8bae\u3002

\n\n

\u6709\u4efb\u4f55\u95ee\u9898\uff0c\u4f60\u53ef\u4ee5\u52a0\u5165\u4ee5\u4e0b\u7fa4\u804a\u54a8\u8be2\uff0c\u4e5f\u53ef\u4ee5\u5728github \u4ed3\u5e93\u4e2d\u53d1\u5e03 Discussions\uff0c\u5982\u679c\u9047\u5230\u95ee\u9898\uff0c\u4e5f\u8bf7\u5728github \u7684 issues\u4e2d\u63d0\u4ea4\uff0c\u6211\u4eec\u4f1a\u5728\u6700\u5feb\u7684\u65f6\u95f4\u89e3\u51b3\u3002

\n" }, { "author": { "url": "member/street000", "name": "street000", "avatar": "https://cdn.v2ex.com/gravatar/c9cbf77b2c201958de61a5e8278ac97c?s=73&d=retro" }, "url": "t/1176594", "date_modified": "2025-12-03T08:24:50+00:00", "content_html": "

\u4e0d\u592a\u5229\u597d Node \u7684\u4e00\u96c6

\n

https://www.anthropic.com/news/anthropic-acquires-bun-as-claude-code-reaches-usd1b-milestone

\n

https://bun.com/blog/bun-joins-anthropic

\n", "date_published": "2025-12-03T04:38:29+00:00", "title": "Anthropic \u6536\u8d2d Bun", "id": "t/1176594" }, { "author": { "url": "member/autumnshine", "name": "autumnshine", "avatar": "https://cdn.v2ex.com/gravatar/5a75019a258fe180c21cb1b0a19b52e1?s=73&d=retro" }, "url": "t/1176480", "title": "\u5173\u4e8e Node.js \u4e2d\u7684\u4e8b\u4ef6\u5faa\u73af\u95ee\u9898\u3002", "id": "t/1176480", "date_published": "2025-12-02T14:04:27+00:00", "content_html": "

\u5927\u4f6c\u4eec\uff0c\u5c0f\u5f1f\u6700\u8fd1\u5728\u5b66\u4e60 Node.js \uff0c\u53d1\u73b0 Promise.then \u4e2d\u7684\u4ee3\u7801\u4f1a\u5148\u4e8e process.nextTick \u6267\u884c\uff0c\u7f51\u4e0a\u8d44\u6599\u666e\u904d\u8bf4\u7684\u662f process.nextTick \u4f1a\u5148\u4e8e\u5fae\u4efb\u52a1\u6267\u884c\uff0c\u8bf7\u95ee\u8fd9\u662f\u4ec0\u4e48\u539f\u56e0...

\n

\u6709\u5982\u4e0b\u4ee3\u7801\uff1a

\n
console.log(\"script start\");\n\nsetTimeout(() => {\n\tconsole.log(\"setTimeout\");\n}, 0);\n\nprocess.nextTick(() => console.log(\"nextTick\"));\n\nnew Promise((resolve, reject) => {\n\tconsole.log(\"promise1\");\n\tresolve(undefined);\n\tconsole.log(\"promise2\");\n}).then(() => {\n\tconsole.log(\"promise3\");\n});\nconsole.log(\"script end\");\n
\n

\u6267\u884c\u7ed3\u679c\u4e3a\uff1a

\n
script start\npromise1\npromise2\nscript end\npromise3 // \u4e3a\u4ec0\u4e48\u4f1a\u5148\u4e8e\u8f93\u51fa\u8fd9\u4e2a\u800c\u4e0d\u662f nextTick \uff1f\uff1f\nnextTick \nsetTimeout\n
\n

\u76f4\u63a5\u4f7f\u7528 Node.js \u6267\u884c ts \u6587\u4ef6\uff0c\u4ee3\u7801\u6267\u884c\u73af\u5883\uff1a\nNode\uff1av25.2.1\nTypeScript\uff1a5.9.3

\n

tsconfig.json

\n
{\n\t\"compilerOptions\": {\n\t\t\"target\": \"ESNext\",\n\t\t\"module\": \"ESNext\",\n\t\t\"esModuleInterop\": true,\n\t\t\"forceConsistentCasingInFileNames\": true,\n\t\t\"strict\": true,\n\t\t\"skipLibCheck\": true,\n\t\t\"noImplicitAny\": true,\n\t\t\"noImplicitReturns\": true,\n\t\t\"strictNullChecks\": true\n\t}\n}\n\n
\n" }, { "author": { "url": "member/nswbmw", "name": "nswbmw", "avatar": "https://cdn.v2ex.com/gravatar/11c35a5b58d99d2c8a950165b795917d?s=73&d=retro" }, "url": "t/1174987", "title": "Hoa - \u4e00\u4e2a\u6781\u7b80 Web \u6846\u67b6", "id": "t/1174987", "date_published": "2025-11-25T09:38:54+00:00", "content_html": "

\u6211\u4f7f\u7528 Koa \u5f88\u591a\u5e74\u4e86\uff0c\u4e00\u76f4\u5f88\u559c\u6b22\u5b83\u7b80\u6d01\u7684\u8bbe\u8ba1\u54f2\u5b66\u3002\u8fd1\u51e0\u5e74\u5728 Cloudflare Worker \u4e0a\u5f00\u53d1\u8f83\u591a\uff0c\u63a5\u89e6\u5230\u4e86 Hono \u3002Hono \u4e5f\u662f\u4e00\u4e2a\u4e0d\u9519\u7684\u6846\u67b6\uff0c\u4f46\u5728\u6df1\u5165\u4f7f\u7528\u540e\uff0c\u6211\u5bf9\u5b83\u7684\u4e00\u4e9b\u8bbe\u8ba1\u7406\u5ff5\u5e76\u4e0d\u662f\u5f88\u8ba4\u540c\uff0c\u4e8e\u662f\u840c\u751f\u4e86\u81ea\u5df1\u9020\u4e2a\u8f6e\u5b50\u7684\u60f3\u6cd5\u3002

\n

\u6211\u4e3a\u65b0\u6846\u67b6\u8bbe\u5b9a\u4e86\u4e09\u6761\u6838\u5fc3\u539f\u5219\uff1a

\n
    \n
  1. \u5fae\u5185\u6838\u67b6\u6784\uff1a\u4e0e Koa \u7c7b\u4f3c\uff0c\u4fdd\u7559\u4e86\u6d0b\u8471\u6a21\u578b\u7684\u4e2d\u95f4\u4ef6\u8bbe\u8ba1\uff0c\u540c\u65f6\u8fd8\u8865\u5145\u4e86\u63d2\u4ef6\u7cfb\u7edf
  2. \n
  3. \u7b26\u5408\u76f4\u89c9\u7684 API \u8bbe\u8ba1\uff1a\u6452\u5f03 Koa \u7684 delegates \u601d\u8def\uff0cAPI \u4e25\u683c\u533a\u5206 ctx/ctx.req/ctx.res \uff0c\u66f4\u52a0\u7b26\u5408\u8bed\u4e49
  4. \n
  5. \u73af\u5883\u65e0\u5173\u6027\uff1a\u53ef\u5728 Node.js \u3001Bun \u3001Deno \u4ee5\u53ca Cloudflare Worker \u3001Vercel \u7b49\u8fb9\u7f18\u73af\u5883\u8fd0\u884c
  6. \n
\n

\u4e8e\u662f Hoa \u8bde\u751f\u4e86\u3002\u76ee\u524d\u6211\u8ddf\u53e6\u4e00\u4e2a\u7ef4\u62a4\u8005\u5df2\u7ecf\u4e3a Hoa \u8865\u5145\u4e86\u8fd1 30 \u4e2a\u5e38\u7528\u4e2d\u95f4\u4ef6\uff0c\u6211\u4e5f\u5df2\u7ecf\u5c06\u624b\u5934\u5927\u90e8\u5206\u9879\u76ee\u4ece Koa \u8fc1\u79fb\u81f3 Hoa \u3002\u4eca\u5929\u5206\u4eab\u51fa\u6765\uff0c\u5e0c\u671b\u66f4\u591a\u4eba\u53bb\u4f7f\u7528\uff0c\u4e5f\u671f\u5f85\u6536\u5230\u66f4\u591a\u53cd\u9988\uff0c\u5171\u540c\u628a Hoa \u6846\u67b6\u6253\u78e8\u5f97\u66f4\u597d\u3002

\n\n

\u7279\u70b9

\n\n

\u5b89\u88c5

\n
npm i hoa --save\n
\n

\u5feb\u901f\u5f00\u59cb

\n
import { Hoa } from 'hoa'\nconst app = new Hoa()\n\napp.use(async (ctx, next) => {\n ctx.res.body = 'Hello, Hoa!'\n})\n\nexport default app\n
\n

License

\n

MIT

\n" }, { "author": { "url": "member/JerryCanDo", "name": "JerryCanDo", "avatar": "https://cdn.v2ex.com/avatar/92ef/e1b8/714999_large.png?m=1760950257" }, "url": "t/1173534", "date_modified": "2025-11-20T00:06:15+00:00", "content_html": "cmd\uff1anode -v
re\uff1a 'node' \u4e0d\u662f\u5185\u90e8\u6216\u5916\u90e8\u547d\u4ee4\uff0c\u4e5f\u4e0d\u662f\u53ef\u8fd0\u884c\u7684\u7a0b\u5e8f\u6216\u6279\u5904\u7406\u6587\u4ef6\u3002

\u5207\u6362\u5230 ide \u7684\u7ec8\u7aef\u6709\u65f6\u5019\u53c8\u6709\u4e86\uff0c\u73b0\u5728\u633a\u70e6\u607c\u7684\uff0c\u6709\u53ef\u80fd cmd \u6709 ide \u6ca1\u6709 \u6709\u65f6\u5019 ide \u6709 cmd \u6ca1\u6709 \u6709\u65f6\u5019\u4e24\u8fb9\u90fd\u6ca1\u6709\u53ea\u80fd\u91cd\u542f\u5927\u6cd5\uff0c\u91cd\u542f\u5927\u6cd5\u4e5f\u6709\u65f6\u5019\u4e5f\u53ef\u80fd\u8fd8\u4f1a\u51fa\u73b0\u8fd9\u60c5\u51b5\uff0c\u6c42\u52a9 v \u53cb\u5927\u795e", "date_published": "2025-11-18T08:17:41+00:00", "title": "\u6709\u6ca1\u6709 v \u53cb\u9047\u5230 windows10 \u4e22\u5931\u7cfb\u7edf\u73af\u5883\u53d8\u91cf\u7684\u95ee\u9898", "id": "t/1173534" }, { "author": { "url": "member/khaliray", "name": "khaliray", "avatar": "https://cdn.v2ex.com/avatar/eac5/b307/551444_large.png?m=1756977461" }, "url": "t/1170534", "date_modified": "2025-11-05T04:31:30+00:00", "content_html": "

\"\" \u8bf7\u6559\u5927\u4f6c\u4eec\uff0c\u4e3a\u4ec0\u4e48\u6211\u7684\u540e\u53f0\u8fdb\u7a0b\u91cc\u4f1a\u4e00\u76f4\u5b58\u5728\u8fd9\u4e2a esbuild \uff0c\u5e76\u4e14\u5360\u7528\u975e\u5e38\u9ad8\u3002pkill -f esbuild \u8fd8\u6740\u4e0d\u6389\uff0c\u53ea\u6709\u6740\u6b7b pid \u624d\u884c\u3002

\n", "date_published": "2025-11-04T15:20:26+00:00", "title": "Esbuild \u8fdb\u7a0b\u5360\u7528\u9ad8", "id": "t/1170534" }, { "author": { "url": "member/wwwatch", "name": "wwwatch", "avatar": "https://cdn.v2ex.com/avatar/0f58/abb8/180290_large.png?m=1734316489" }, "url": "t/1169528", "title": "\u6709\u6ca1\u6709\u63a8\u8350\u7684 Nodejs \u7684 sass \u591a\u79df\u6237\u7cfb\u7edf", "id": "t/1169528", "date_published": "2025-10-30T12:21:26+00:00", "content_html": "

Java \u4e0b\u6211\u77e5\u9053\u6709\u4e00\u5806\u6846\u67b6\uff0c\u6bd4\u5982\u57fa\u4e8e ruoyi \u7684\u4e00\u5806\u884d\u751f\u6846\u67b6\u3002\u57fa\u4e8e Nodejs \u7684\u597d\u50cf\u6ca1\u89c1\u5230\u6709\uff0c\u57fa\u4e8e\u5b57\u6bb5\u9694\u79bb\u7684\u591a\u79df\u6237\u7cfb\u7edf\u3002

\n" }, { "author": { "url": "member/BeautifulSoap", "name": "BeautifulSoap", "avatar": "https://cdn.v2ex.com/avatar/1e0f/48e8/266237_large.png?m=1760788101" }, "url": "t/1166656", "date_modified": "2025-10-19T01:01:47+00:00", "content_html": "

\u5047\u8bbe\u5728 ./utils/calcute.ts \u4e2d\u6709\u4e00\u4e2a\u5de5\u5177\u51fd\u6570 add()

\n
export function add(a: number, b: number): number {\n return a + b;\n}\n
\n

\u7136\u540e\u6211\u4eec\u5728 main.ts \u4e2d\u9700\u8981\u4f7f\u7528\u8fd9\u4e2a add \u51fd\u6570

\n

\u5199\u6cd5 1, import \u4e0d\u5e26\u6269\u5c55\u540d\uff1a

\n

tsconfig \u914d\u7f6e module=esnext \uff0c\u7136\u540e\u5047\u8bbe\u6709\u5982\u4e0b main.ts \u6587\u4ef6

\n
import { add } from \"./utils/calcute\";\n\nadd(1,2)\n
\n

\u4f7f\u7528 tsc \u7f16\u8bd1\u540e\u4f7f\u7528 node \u8fd0\u884c\u7f16\u8bd1\u540e\u7684 js \u6587\u4ef6\u4f1a\u62a5\u9519

\n
\nnode ./dist/main.js\n\n... \u7701\u7565\n\n code: 'ERR_UNSUPPORTED_DIR_IMPORT',\n url: 'file:///home/xxxxxx/dist/utils/calcute'\n \n
\n

\u539f\u56e0\u662f\u73b0\u5728\u7684 node \u5904\u7406 esm \u7684 import \u9700\u8981\u6307\u5b9a\u5177\u4f53\u6587\u4ef6\u540d\uff08\u5373\u7c7b\u4f3c import ./utils/calcute.js \uff09\u3002\u4e0d\u5199\u6269\u5c55\u540d\u7684 import \u4f1a\u62a5\u9519

\n

\u800c typescript \u7f16\u8bd1\u4ee3\u7801\u5bf9 import \u5185 from \"xxxx\" \u7684\u90e8\u5206\u662f\u4e0d\u4f1a\u505a\u4efb\u4f55\u5904\u7406\u76f4\u63a5\u4fdd\u7559\u7684\u3002\u6309\u7167 ts \u5b98\u65b9\u7684\u610f\u601d\u5c31\u662f\u8fd9\u90e8\u5206\u662f\u6a21\u5757\u89e3\u6790\uff0c\u4e0d\u5e94\u8be5\u662f typescript \u7684\u5de5\u4f5c\u800c\u5e94\u4ea4\u7ed9 js \u8fd0\u884c\u65f6\uff08\u5982 node \u3001\u6d4f\u89c8\u5668\uff09\u81ea\u5df1\u5904\u7406\uff0c\u6240\u4ee5 tsc \u7f16\u8bd1 ts \u6587\u4ef6\u662f\u4f1a\u5b8c\u6574\u4fdd\u7559\u8fd9\u90e8\u5206\u4e0d\u505a\u4efb\u4f55\u53d8\u52a8\u7684

\n

\u57fa\u4e8e\u8fd9\u79cd\u65b9\u9488\uff0c\u4e8e\u662f\u5c31\u6709\u4e86\u4e24\u79cd\u89e3\u6cd5

\n
    \n
  1. \u653e\u5f03 tsc \u7f16\u8bd1\u4f7f\u7528 bundle
  2. \n
  3. \u4e0b\u9762\u7684\u5199\u6cd5 2
  4. \n
\n

\u5199\u6cd5 2\uff1aimport .js

\n

tsconfig \u914d\u7f6e module=nodenext \u548c moduleResolution=nodenext \uff0c\u7136\u540e main.ts \u5185\u5bb9\u5982\u4e0b

\n
import { add } from \"./utils/calcute.js\"; // \u9700\u8981\u6dfb\u52a0 .js \u6269\u5c55\u540d\n\nadd(1,2)\n
\n

\u8bf4\u771f\u7684\uff0c\u5f53\u5e74\u6211\u63a5\u89e6\u5230\u8fd9\u79cd\u5199\u6cd5\u7684\u65f6\u5019\u662f\u5927\u53d7\u9707\u64bc\u7684\u3002 \u5728 ts \u6587\u4ef6\u4e2d\u5199 import .js \u5b9e\u5728\u8fc7\u4e8e\u4e11\u964b\u4e86\u3002\u6211\u4e0d\u89e3\u3001\u6211\u4e0d\u9002\u5e94\u3001\u6211\u65e0\u6cd5\u63a5\u53d7

\n

\u4f46\u8fd9\u6837\u7684\u4ee3\u7801\u7ecf\u8fc7 tsc \u7f16\u8bd1\u540e\u5c31\u80fd\u6b63\u5e38\u88ab node \u6267\u884c\u4e86\uff0c\u6211\u4e5f\u53ea\u80fd\u634f\u7740\u9f3b\u5b50\u7528\u4e86

\n

\u672c\u6765\u4ee5\u4e3a esm \u7684\u95ee\u9898\u4e5f\u5c31\u8fd9\u6837\u4e86\uff0c\u4f46\u6ca1\u60f3\u5230\u5230\u4e86 2025 \u5e74\u5c31\u4e71\u5957\u4e86

\n

\u5199\u6cd5 3: import .ts

\n

\u56e0\u4e3a bun, deno \u7684\u7ade\u4e89\uff0c\u4e0d\u601d\u8fdb\u53d6\u7684 node \u7ec8\u4e8e\u5f00\u59cb\u8fed\u4ee3\u8d77\u529f\u80fd\u4e86\u3002\u751a\u81f3\u8fd8\u7834\u5929\u8352\u5730\u6dfb\u52a0\u4e86\u76f4\u63a5\u6267\u884c typescript \u4ee3\u7801\u7684\u529f\u80fd\uff08\u8fd0\u884c\u7684\u65f6\u5019\u76f4\u63a5\u4e22\u5f03\u7c7b\u578b\u4fe1\u606f\u628a ts \u5f53 js \u8dd1\uff09

\n

\u8fd9\u4e2a\u529f\u80fd\u73b0\u5728\u5728\u5728\u65b0 node \u4e2d\u5df2\u7ecf\u9ed8\u8ba4\u5f00\u542f\u53ef\u7528\u4e86\uff0c\u5e76\u4e14 typescript \u4e5f\u4e3a\u4e86\u8fd9\u4e2a\u529f\u80fd\u6dfb\u52a0\u591a\u4e2a\u66f4\u65b0\u3002\u6240\u4ee5\u53ef\u4ee5\u9884\u89c1\u4eca\u540e\u7528 node \u76f4\u63a5\u6267\u884c ts \u4f1a\u591a\u8d77\u6765

\n

\u7136\u540e\uff0c\u8fd9\u4e2a\u529f\u80fd\u5728 esm \u4e0a\u5c31\u4e0d\u51fa\u610f\u5916\u5f97\u51fa\u610f\u5916\u4e86\u3002\u8fd8\u662f\u4e0a\u9762\u7684\u4ee3\u7801 main.ts \u5185\u5bb9\u5982\u4e0b\uff1a

\n
import { add } from \"./utils/calcute.js\"; // \u9700\u8981\u6dfb\u52a0 .js \u6269\u5c55\u540d\n\nadd(1,2)\n
\n

\u4f7f\u7528 node main.ts \u6267\u884c\u540e\u76f4\u63a5\u62a5\u9519

\n
\nnode main.ts\n\n... \u7701\u7565\n\n code: 'ERR_MODULE_NOT_FOUND',\n url: 'file:///home/xxxxxxxx/utils/calcute.js'\n\n
\n

\u55ef\uff0c\u56e0\u4e3a\u6a21\u5757\u7684\u4ee3\u7801\u4f4d\u4e8e\u6587\u4ef6 utils/calcute.ts \u4e2d\uff0c\u800c import \u8bed\u53e5\u4e2d\u5199\u7684\u662f ./utils/calcute.js\uff0c\u6240\u4ee5 node \u7406\u6240\u5f53\u7136\u7684\u627e\u4e0d\u5230\u5bf9\u5e94\u7684\u6a21\u5757\u6587\u4ef6\u62a5\u9519\u4e86

\n

\u6240\u4ee5\u4e3a\u4e86\u89e3\u51b3\u8fd9\u4e2a\u95ee\u9898\uff0ctsconfig \u540e\u6765\u6dfb\u52a0\u4e86\u4e00\u4e2a\u9009\u9879 allowImportingTsExtensions \uff0c\u5f00\u542f\u540e\u5728 main.ts \u4e2d\u9700\u8981\u5c06 import \u6539\u5199\u6210 import .ts \u7684\u5f62\u5f0f

\n
import { add } from \"./utils/calcute.ts\"; // \u9700\u8981 import .ts \uff0c\u800c\u4e0d\u662f.js\n\nadd(1,2)\n
\n

\u55ef\uff0c\u5f53\u5e74 typescript \u7684\u56de\u65cb\u9556\u5c31\u8fd9\u4e48\u7838\u4e86\u56de\u6765\uff0c\u73b0\u5728\u6211\u4eec\u53c8\u5fc5\u987b\u5728 ts \u6587\u4ef6\u4e2d\u5199 import .ts \u4e86\u3002\u5e76\u4e14\u4e3a\u4e86\u517c\u5bb9\u8fd9\u79cd\u5199\u6cd5 typesript \u73b0\u5728\u8fd8\u4e0d\u5f97\u4e0d\u6dfb\u52a0\u65b0\u7684\u7f16\u8bd1\u9009\u9879 allowImportingTsExtensions \u6765\u5141\u8bb8\u5728 ts \u6587\u4ef6\u4e2d import .ts

\n

\u4f46\u662f\uff0c\u8fd9\u6709\u4e2a\u95ee\u9898\uff0c\u542f\u7528\u8fd9\u4e2a\u9009\u9879\u5fc5\u987b\u4e5f\u542f\u7528 noEmit \uff0c\u4e5f\u5c31\u662f\u8bf4\u5728 typescript \u5b98\u65b9\u90a3\u7684\u8bf4\u6cd5\u662f\uff1a\u6211\u4eec\u6ca1\u6709\u88ab\u6253\u8138\u554a\uff0c\u6211\u4eec\u4f9d\u65e7\u4e0d\u5904\u7406 import \u7684\u5185\u5bb9\uff0c\u4f60\u60f3 import .ts \u53ef\u4ee5\uff0c\u4f46\u662f\u4f60\u8fd9\u6837\u5199\u4e86\u7684\u8bdd\u5c31\u522b\u7528\u6211\u4eec\u7684 tsc \u6765\u628a\u8fd9\u79cd\u4ee3\u7801\u7f16\u8bd1\u6210 js \u4e86

\n

\u4f46\u95ee\u9898\u662f\u5b9e\u9645\u4e0a\u5f00\u53d1\u4e2d\uff0c\u4f7f\u7528 node \u76f4\u63a5\u6267\u884c ts \u6587\u4ef6\u6d4b\u8bd5\uff0c\u7136\u540e\u5728\u751f\u4ea7\u73af\u5883\u4e2d\u4f7f\u7528 tsc \u6216\u5176\u4ed6\u5de5\u5177\u7f16\u8bd1\u6210 js \u8fd0\u884c\u4f1a\u5f88\u5e38\u89c1

\n

\u4e8e\u662f\u5982\u679c\u4f60\u60f3\u76f4\u63a5 node \u6267\u884c ts \u4ee3\u7801\uff0c\u90a3\u5c31\u5f97\u653e\u5f03\u5c06\u4f7f\u7528 tsc \u5c06\u4ee3\u7801\u7f16\u8bd1\u4e3a js

\n

\u6240\u4ee5\u5927\u5bb6\u600e\u4e48\u9009

\n

\u76ee\u524d\u8fd9 esm import \u5199\u6cd5\u5df2\u7ecf\u4e71\u6210\u8fd9\u6837\u4e86\uff0c\u5927\u5bb6\u5e73\u65f6\u4f1a\u600e\u4e48\u9009\uff1f

\n", "date_published": "2025-10-18T11:51:31+00:00", "title": "2025 \u5e74 node \u9879\u76ee\uff0c\u4e71\u6210\u4e00\u9505\u7ca5\u7684 typescript ESM import \u5199\u6cd5\u8be5\u600e\u4e48\u9009\uff1f", "id": "t/1166656" }, { "author": { "url": "member/HRTops", "name": "HRTops", "avatar": "https://cdn.v2ex.com/avatar/91d0/34bd/65032_large.png?m=1775044977" }, "url": "t/1165908", "title": "[EvanNav 6.3.1] \u5982\u4f55\u5220\u9664\u52a0\u8f7d\u9875\u9762\uff0c\u8ba9 Nav \u66f4\u7b26\u5408\u4f60\u7684\u9700\u6c42\u2049\ufe0f", "id": "t/1165908", "date_published": "2025-10-15T12:40:22+00:00", "content_html": "

\"|1920x1280\"

\n

EvanNav \u5b98\u7f51\uff08\u5df2\u7ecf\u53bb\u9664\u52a0\u8f7d\u9875\uff09

\n

https://evan.plus

\n

\u6709\u4e9b\u670b\u53cb\u5e0c\u671b EvanNav \u4e0d\u8981\u6709\u52a0\u8f7d\u9875\u9762\uff0c\u4e8e\u662f\u505a\u4e86\u8fd9\u4e2a\u5c0f\u5c0f\u6559\u7a0b\uff01

\n

\u597d\u7684\uff0c\u4e3a\u4e86\u5220\u9664\u52a0\u8f7d\u9875\uff0c\u60a8\u9700\u8981\u5728\u4ee5\u4e0b\u6587\u4ef6\u4e2d\u8fdb\u884c\u4ee3\u7801\u4fee\u6539\uff1a

\n

1. public/index.html

\n

\u5220\u9664\u4ee5\u4e0b\u4ee3\u7801\u5757\uff1a

\n

HTML

\n
<!-- \u52a0\u8f7d\u7f13\u51b2\u9875 -->\n<div class=\"loading-screen\" id=\"loading-screen\">\n <div class=\"loading-icon\"></div>\n <div class=\"loading-title\" id=\"loading-title\"></div>\n <div class=\"loading-progress\">\n <div class=\"progress-bar\" id=\"progress-bar\"></div>\n </div>\n</div>\n
\n

2. public/script.js

\n

\u67e5\u627e\u5e76\u5220\u9664\u4ee5\u4e0b\u4ee3\u7801\u5757\uff1a

\n

Javascript

\n
// \u4f18\u5148\u52a0\u8f7d\u81ea\u5b9a\u4e49\u7f51\u7ad9\u540d\u79f0\uff0c\u907f\u514d\u5ef6\u8fdf\nconst loadingTitle = utils.getElement('loading-title');\nif (loadingTitle) {\n loadingTitle.textCOntent= settings.websiteTitle || 'My Website Favorites';\n}\n
\n

\u7136\u540e\uff0c\u5c06\u6587\u4ef6\u672b\u5c3e\u7684\uff1a

\n

Javascript

\n
document.addEventListener('DOMContentLoaded', init);\n
\n

\u66ff\u6362\u4e3a\uff1a

\n

Javascript

\n
document.addEventListener('DOMContentLoaded', async function() {\n await init();\n document.getElementById('frontend').style.opacity = '1';\n});\n
\n

3. public/styles.css

\n

\u5220\u9664\u6216\u6ce8\u91ca\u6389\u4ee5\u4e0b\u4e0e\u52a0\u8f7d\u9875\u9762\u76f8\u5173\u7684 CSS \u89c4\u5219\uff1a

\n

CSS

\n
.loading-screen {\n position: fixed;\n top: 0;\n left: 0;\n width: 100%;\n height: 100%;\n background: #f8fafc;\n display: flex;\n flex-direction: column;\n justify-content: center;\n align-items: center;\n z-index: 9999;\n transition: opacity 0.5s ease;\n}\n\n.loading-icon {\n width: 50px;\n height: 50px;\n border: 4px solid #1e40af;\n border-top-color: transparent;\n border-radius: 50%;\n animation: spin 1s linear infinite;\n}\n\n.loading-title {\n margin-top: 1.5rem;\n font-size: 1.2rem;\n font-weight: 600;\n color: #1e40af;\n}\n\n.loading-progress {\n width: 200px;\n height: 8px;\n background: #e2e8f0;\n border-radius: 4px;\n margin-top: 1.5rem;\n overflow: hidden;\n}\n\n.progress-bar {\n width: 0;\n height: 100%;\n background: #1e40af;\n transition: width 0.2s ease;\n}\n\n@keyframes spin {\n to {\n transform: rotate(360deg);\n }\n}\n
\n

\u7ecf\u8fc7\u4ee5\u4e0a\u4e09\u90e8\u5373\u53ef\u5220\u9664\u52a0\u8f7d\u9875\u9762\uff01\u5207\u8bb0\uff0c\u66f4\u6539\u6587\u4ef6\u524d\u300c\u5907\u4efd\u6587\u4ef6\u300d\uff01

\n

\u6211\u7684 blog \u539f\u6587\uff1a\nhttps://www.evan.xin/4074/

\n" }, { "author": { "url": "member/xkwdm", "name": "xkwdm", "avatar": "https://cdn.v2ex.com/avatar/88b3/23fe/373377_large.png?m=1768448883" }, "url": "t/1165028", "date_modified": "2025-10-14T04:08:51+00:00", "content_html": "

\u5220\u9664 node_modules \u6587\u4ef6\u5939\u975e\u5e38\u8017\u65f6\u3002\u7528\u4f19\u706b\u7ed2\u7684\u7c89\u788e\u4e5f\u6162\u3002\u5927\u4f19\u513f\u6709\u6ca1\u6709\u597d\u7528\u7684\u8f6f\u4ef6\u548c\u65b9\u6cd5\u554a\uff1f

\n

\u611f\u8c22\u5404\u4f4d\u5927\u4f6c\u7684\u6307\u70b9 \ud83d\ude4f

\n", "date_published": "2025-10-14T01:33:04+00:00", "title": "\u5220\u9664 node_modules \u6587\u4ef6\u5939\u975e\u5e38\u8017\u65f6", "id": "t/1165028" }, { "author": { "url": "member/keelii", "name": "keelii", "avatar": "https://cdn.v2ex.com/avatar/1592/1040/7682_large.png?m=1653312302" }, "url": "t/1163307", "title": "Node.JS \u4f5c\u8005 Ryan Dahl \u7684\u6545\u4e8b", "id": "t/1163307", "date_published": "2025-10-04T00:51:55+00:00", "content_html": "

\u4eca\u5929\u6211\u60f3\u6765\u804a\u804a Node.js \u7684\u4f5c\u8005 Ryan Dahl(ry)\uff0c\u524d\u4e0d\u4e45\u5728\u5b83\u7684\u4e00\u4e2a\u6f14\u8bb2\u4e3b\u9898\u4e0a\u4e86\u89e3\u5230\u4e86\u4e00\u4e9b\u5173\u4e8e\u4ed6\u7684\u6545\u4e8b\uff0c\u7ed3\u5408\u6211\u81ea\u5df1\u7684\u4e00\u4e9b\u8ba4\u77e5\uff0c\u6211\u60f3 ry \u7684\u6545\u4e8b\u5bf9\u4e8e\u6211\u4eec\u662f\u6709\u6240\u542f\u53d1\u7684\uff0c\u65e0\u8bba\u662f\u7f16\u7a0b\u3001\u5de5\u4f5c\u8fd8\u662f\u751f\u6d3b\u65b9\u5f0f\u3002

\n

\u50cf ry \u8fd9\u6837\u7684\u7a0b\u5e8f\u5458\uff0c\u6211\u89c9\u5f97\u5de5\u7a0b\u5e08\u66f4\u7b26\u5408\u4ed6\u7684 title \uff0cNode.js \u662f\u57282009 \u5e74 5 \u6708 28 \u65e5 \u53d1\u5e03 0.0.1 \u7248\u672c\u7684\uff0c\u5df2\u7ecf\u6709 16 \u5e74\u7684\u5386\u53f2\u4e86\u3002\u5728\u8fd9\u671f\u95f4\u9664\u4e86\u4e00\u4e9b\u5bf9\u5916\u7684\u6280\u672f\u7c7b\u578b\u7684\u5206\u4eab\u548c\u6f14\u8bb2\u4e4b\u5916\uff0c\u5f88\u96be\u627e\u5230\u548c\u4ed6\u76f8\u5173\u7684\u8d44\u6599\u3002\u4f46\u662f\u8fd9\u5e76\u4e0d\u59a8\u788d\u6211\u4eec\u4ece\u4ed6\u7684\u4f5c\u54c1\u548c\u8fd9 16 \u5e74\u95f4\u505a\u7684\u4e8b\u60c5\u53bb\u4e86\u89e3\u4ed6\u3002

\n

\u8fd9\u7bc7\u6587\u7ae0\u4f1a\u987a\u7740 Node.js: The Documentary | An origin story \u7684\u65f6\u95f4\u7ebf\u603b\u7ed3\u548c\u5f52\u7eb3\u4e0b ry \u7684\u7ecf\u5386\u3002

\n

\u65e9\u4e9b\u5e74 ry \u662f\u7ebd\u7ea6\u5317\u90e8\u7684\u4e00\u540d\u6570\u5b66\u7814\u7a76\u751f\uff0c\u5e76\u4e14\u51c6\u5907\u653b\u8bfb\u535a\u58eb\u5b66\u3002\u5b83\u5728\u89c6\u9891\u4e2d\u8bb2\u5230\uff0c\u4ed6\u867d\u7136\u559c\u6b22\u6570\u5b66\u8fd9\u4e2a\u9886\u57df\uff0c\u4f46\u662f\u5b9e\u9645\u4e0a\u4ed6\u5e76\u6ca1\u6709\u505a\u66f4\u591a\u770b\u5f97\u89c1\u7684\u3001\u80fd\u5b9e\u8df5\u7684\u4e8b\u60c5\u3002\u8fd9\u548c\u6211\u4eec\u8ba4\u77e5\u7684\u6570\u5b66\u8fd9\u95e8\u5b66\u79d1\u662f\u4e00\u81f4\u7684\u3002\u4ed6\u8bf4\u4ed6\u60f3\u505a\u4e00\u4e9b\u4e8b\u60c5\u662f\u4e0e\u4eba\u7c7b\u6b63\u5728\u53d1\u751f\u7684\u4e1c\u897f\u76f8\u5173\uff0c\u7136\u540e\u4ed6\u5c31\u9000\u5b66\u4e86\u3002

\n

\"ry-gf.png\"

\n

\u9000\u5b66\u540e\u4ed6\u5728 Craigslist \uff08\u7c7b\u4f3c\u5f53\u5e74\u4e2d\u56fd\u7684\u9ec4\u9875\u7f51\u7ad9\uff0c\u767e\u59d3\u7f51\u4e4b\u7c7b\u7684\uff09 \u4e0a\u627e\u5230\u4e86\u4ed6\u7684\u7f16\u7a0b\u4e4b\u8def\uff0c\u5f53\u65f6\u4ed6\u5e94\u8058\u4e86\u4e00\u5bb6\u6ed1\u96ea\u677f\u516c\u53f8\uff0c\u505a\u4e00\u4e9b\u8425\u9500\u7f51\u7ad9\uff0c\u5f53\u7136\u8fd9\u5e76\u4e0d\u662f\u4e00\u4e9b\u770b\u8d77\u6765\u5f88\u6709\u610f\u601d\u7684\u4e8b\u60c5\u3002\u4ed6\u628a\u6ce8\u610f\u529b\u8f6c\u5411\u4e86\u66f4\u62bd\u8c61\u7684\u4e8b\u60c5\u4e0a\uff0c\u4ed6\u4f7f\u7528 Ruby on Rails \u5b9e\u73b0\u4e86\u6574\u4e2a\u7f51\u7ad9\uff0c\u53d1\u73b0\u5b83\u5f88\u6162\uff0c\u7136\u540e\u4ed6\u5c31\u7814\u7a76 nginx \u6a21\u5757\uff0c\u6bd4\u8f83\u5e95\u5c42\u7684 web \u6280\u672f\u6808\u3002

\n

\u63a5\u7740\u4ed6\u9047\u5230\u4e86\u81ea\u5df1\u81ea\u5df1\u7684\u5973\u670b\u53cb\uff0c\u5e76\u968f\u5979\u5973\u670b\u53cb\u4e00\u8d77\u53bb\u4e86\u5fb7\u56fd\uff0c\u5728\u79d1\u9686\u751f\u6d3b\u4e86\u5927\u7ea6\u4e24\u5e74\uff0c\u56e0\u4e3a\u79d1\u9686\u6d88\u8d39\u6bd4\u8f83\u4f4e\uff0c\u79df\u623f\u6bcf\u6708\u53ea\u8981 400 \u5200\uff0c\u8fd9\u8ba9\u4ed6\u6709\u8db3\u591f\u7684\u7a7a\u95f4\u548c\u65f6\u95f4\u53bb\u601d\u8003\u4e00\u4e9b\u4e8b\u60c5\uff0c\u53bb\u505a\u4e00\u4e9b\u81ea\u5df1\u60f3\u505a\u7684\u9879\u76ee\u3002\u5e76\u4e14\u4ed6\u8ba4\u4e3a\u8fd9\u662f\u4e00\u6bb5 20 \u591a\u5c81\u65f6\u7684\u6109\u5feb\u7684\u65f6\u5149\u3002

\n

\u4ece V8 \u53d1\u5e03\u7684\u65f6\u5019\u4ed6\u5c31\u5728\u8003\u8651\u4e00\u4e2a\u95ee\u9898\uff1aJavascript \u4e0e\u975e\u963b\u585e\u3002\u4ed6\u5728\u89c6\u9891\u4e2d\u4e5f\u8bf4\u5230\uff1a\u8fd9\u662f\u4e00\u4e2a\u5728\u6b63\u786e\u7684\u65f6\u95f4\u601d\u8003\u6b63\u786e\u7684\u4e8b\u60c5\u3002

\n

ry \u5446\u5728\u79d1\u9686\u7684\u90a3\u6bb5\u65f6\u95f4\u5927\u6982\u4ece 2 \u6708\uff5e 10 \u6708\u7684\u65f6\u5019\u5168\u804c\u5f00\u53d1\u6784\u5efa\u4e86\u7b2c\u4e00\u4e2a\u7248\u672c\u7684 Node.js

\n

Isaac Schlueter(izs) \u5728 Node.js \u9996\u6b21\u53d1\u5e03\u7684\u65f6\u5019\u662f yahoo \u7684\u5de5\u7a0b\u5e08\uff0c\u8fd8\u56e0\u4e3a\u5f53\u65f6\u7684\u5de5\u4f5c\u603b\u662f\u8981\u5728 PHP \u548c Javascript \u4e4b\u95f4\u5207\u6362\u800c\u611f\u5230\u6cae\u4e27\uff0c\u6240\u4ee5\u4ed6\u4f1a\u8003\u8651\u4e3a\u4ec0\u4e48\u4e0d\u4f7f\u7528 Javascript \u6765\u505a\u670d\u52a1\u7aef\u7684\u7f16\u7a0b\u8bed\u8a00\u3002\u5f53\u65f6\u4e5f\u6709\u4e00\u5c0f\u90e8\u5206\u4eba\u5728\u8bd5\u56fe\u5c06 Javascript \u5b9e\u73b0\u6210\u670d\u52a1\u7aef\u7f16\u7a0b\u8bed\u8a00\uff0c\u6bd4\u5982\uff1aServer.js,Jaxer,RingoJS \u3002\u5728\u5f53\u65f6 Javascript \u670d\u52a1\u7aef\u80fd\u529b\u5df2\u7ecf\u6709\u4e00\u4e9b\u7aef\u502a\u4e86\u3002Node.js \u7684\u51fa\u73b0\u6709\u70b9\u51fa\u4e4e\u610f\u6599\u3002Isaac Schlueter \u8bf4\u4ed6\u8ba4\u4e3a

\n
\n

ry \u9009\u62e9 Javascript \u5e76\u4e0d\u662f\u56e0\u4e3a\u4ed6\u559c\u6b22 Javascript \uff0c\u800c\u662f\u56e0\u4e3a Javascript \u5f88\u5408\u9002\u3002

\n
\n

ry \u8bf4\u5728\u9009\u62e9 Javascript \u4e4b\u524d\u4e5f\u7814\u7a76\u4e86\u50cf Python,Lua, Haskell \u8fd9\u6837\u7684\u7f16\u7a0b\u8bed\u8a00\u3002\u4f46\u662f\u6709\u4e00\u5929\u548c\u670b\u53cb\u5750\u5728\u4e00\u8d77\uff0c\u7a81\u7136\u4e4b\u95f4\u5c31\u6709\u4e86\u4e00\u4e2a\u60f3\u6cd5\uff1a\u201c\u6211\u9760 Javascript \uff0c\u5c31\u5e94\u8be5\u662f Javascript\u201d\u3002\u5c31\u5728\u90a3\u4e00\u523b\u4ed6\u975e\u5e38\u6e05\u695a\u7684\u786e\u5b9a\u4e86\u662f Javascript \u3002

\n

\u5f53\u65f6\u5728\u5176\u5b83\u7f16\u8f91\u8bed\u8a00\u4e2d\u57fa\u672c\u4e0a\u90fd\u6709\u4e86\u4e00\u5b9a\u7684\u8303\u5f0f\u3002\u4f46 Javascript \u8fd8\u662f\u7a7a\u767d\u3002

\n

\u975e\u963b\u585e IO \u7684\u5b9e\u73b0\u5728\u5176\u5b83\u7684\u7f16\u7a0b\u8bed\u8a00\u5b9e\u73b0\u90fd\u4f1a\u6709\u5f88\u5927\u7684\u963b\u529b\uff0c\u6bd4\u5982\u5728 Python \u4e2d\u6253\u5f00\u4e00\u4e2a\u6587\u4ef6\uff0c\u5927\u5bb6\u5df2\u7ecf\u4e60\u60ef\u4e86\u4f7f\u7528\u4e0b\u9762\u7684\u540c\u6b65 IO \u8303\u5f0f\u6765\u5b9e\u73b0\uff1a

\n
with open(\"filename.txt\", \"r) as file:\n\tcOntent= file.read()\n
\n

\u6240\u4ee5\u4f7f\u7528 Python \u6765\u5b9e\u73b0\u663e\u7136\u4e0d\u662f\u4e00\u4e2a\u597d\u7684\u9009\u62e9\uff0c\u56e0\u4e3a\u8fd9\u610f\u5473\u7740 Python \u5f00\u53d1\u8005\u9700\u8981\u8f6c\u6362\u7f16\u7a0b\u4e60\u60ef\u3002

\n

\u540e\u6765\u8d8a\u6765\u8d8a\u591a\u7684\u4eba\u77e5\u9053\u4e86 Node.js \uff0c\u4f46\u662f\u5f53\u65f6\u8fd8\u6ca1\u6709\u5305\u7ba1\u7406\u7cfb\u7edf\uff0c**izs \u5c31\u521b\u5efa\u4e86 [NPM](NPM)**\uff0c\u6700\u5f00\u59cb NPM \u7684\u6e90\u4ee3\u7801\u662f\u4e00\u4e9b shell \u811a\u672c\uff0c\u5f88\u591a\u4ee3\u7801\u6765\u81ea\u4e8e Yinst - yahoo \u5185\u90e8\u7528\u7684\u7684\u5305\u7ba1\u7406\u5668\u3002

\n

ry \u5728 JSConf EU \u4e0a\u7684\u4e3b\u9898\u6f14 Ryan Dahl: Original Node.js presentation \u9996\u6b21\u5bf9\u5916\u516c\u5f00 Node.js \uff0c\u53ef\u4ee5\u770b\u51fa\u6765\u5f53\u65f6\u7684\u4ed6\u8fd8\u662f\u5f88\u9752\u6da9\u3001\u5f88\u7d27\u5f20\u7684\u3002

\n

\"ry.png\"

\n

ry \u8bf4\u4ed6\u53ea\u662f JSConf \u4e0a\u7684\u4e00\u4e2a\u666e\u901a\u6f14\u8bb2\u8005\uff0c\u4f46\u662f\u4ed6\u5df2\u7ecf\u4e3a\u4e86\u8fd9\u4e2a\u6f14\u8bb2\u63d0\u524d\u51e0\u5468\u505a\u4e86\u5145\u5206\u7684\u51c6\u5907\u3002\u6bcf\u4e2a\u4eba\u90fd\u5728\u6f14\u793a\u81ea\u5df1\u7684 \u73a9\u5177 \u9879\u76ee\uff0c\u800c\u53ea\u6709\u4ed6\u5199\u7684 Node.js \u662f\u771f\u6b63\u4e25\u8083\u7684\u9879\u76ee\u3002\u5b83\u5728\u73b0\u573a\u5c55\u793a\u4e86\u4e00\u4e2a\u4f7f\u7528 Node.js \u6784\u5efa\u7684 IRC \u9891\u9053\u670d\u52a1\u5668\uff0c\u5f53\u573a\u5728\u540c\u4e00\u4e2a\u7f51\u7edc\u7684\u89c2\u4f17\u4e5f\u53ef\u4ee5\u94fe\u63a5\u8fdb\u53bb\u53d1\u6d88\u606f\u3002

\n

\u5728 Node.js \u521b\u5efa\u7684\u521d\u671f\uff0c\u7a0b\u5e8f\u5458\u8fd8\u6ca1\u6709\u4e00\u4e9b\u5f88\u597d\u7684\u6c9f\u901a\u5de5\u5177\uff0c\u6ca1\u6709 slack, discord, github \u7684\u529f\u80fd\u8fd8\u975e\u5e38\u7684\u539f\u59cb\uff0c\u4e5f\u6ca1\u6709\u4efb\u4f55\u6301\u7eed\u96c6\u6210\u7684\u5de5\u5177\u3002\u5927\u5bb6\u90fd\u901a\u8fc7\u7535\u5b50\u90ae\u4ef6\u5c06\u8865\u4e01\u53d1\u7ed9 ry \uff0c\u7136\u540e\u624b\u52a8\u5408\u5e76\u5230\u4ee3\u7801\u4ed3\u5e93\u4e2d\uff0cry \u5c31\u50cf\u662f\u4e2a\u4eba\u5de5\u7684 CI \u5de5\u5177\u4e00\u6837\uff0c\u624b\u52a8\u6253\u8865\u4e01\uff0c\u624b\u52a8\u6d4b\u8bd5\u3002

\n

JSConf \u6f14\u8bb2\u4e4b\u540e ry \u8fd8\u5728\u79d1\u9686\uff0c\u5f53\u65f6\u5df2\u7ecf\u6709\u5f88\u591a\u516c\u53f8\u8054\u7cfb\u4ed6\u8bf4\u5bf9\u4ed6\u7684\u9879\u76ee\u611f\u5174\u8da3\u3002\u4ed6\u5c31\u98de\u5230\u65e7\u91d1\u5c71\u53bb\u548c\u5bf9\u65b9\u804a\uff0c\u4e5f\u662f\u4e3a\u4e86\u8fd9\u4e2a\u9879\u76ee\u80fd\u7ee7\u7eed\u4e0b\u53bb\u627e\u4e00\u4e9b\u8d44\u91d1\u652f\u6301\u3002\u6700\u540e joyent \u63d0\u51fa\u4e86\u597d\u7684\u65b9\u6848\u3002joyent \u662f\u4e00\u4e2a\u4e91\u670d\u52a1\u63d0\u4f9b\u5546\uff0c\u4ed6\u4eec\u60f3\u5728\u81ea\u5df1\u7684\u670d\u52a1\u4e0a\u8fd0\u884c node \u5e94\u7528\u7a0b\u5e8f\u3002

\n

\u7136\u540e ry \u5c31\u642c\u5230\u4e86\u65e7\u91d1\u5c71\uff0c\u5168\u804c\u4ece\u4e8b Node \u5de5\u4f5c\u3002\u4ed6\u5728 joyent \u65f6\u9664\u4e86 Node \u6ca1\u6709\u4efb\u4f55\u5176\u5b83\u5de5\u4f5c\u3002

\n

Bert Belder \u5728\u4e00\u5bb6\u521d\u521b\u516c\u53f8\uff0c\u4e3a\u5efa\u7b51\u516c\u53f8\u505a\u81ea\u52a8\u5316\uff0c\u4ed6\u4eec\u5fc5\u987b\u8fdb\u884c\u4e00\u4e9b\u590d\u6742\u7684\u8ba1\u7b97\uff0c\u4ed6\u4eec\u4e3a\u524d\u7aef\u5b9e\u73b0\u8fd9\u4e9b\u8ba1\u7b97\u529f\u80fd\u3002\u4f7f\u7528 Node.js \u5728\u4e00\u591c\u4e4b\u95f4\u5b8c\u6210\u4e86\u4ed6\u4eec\u7684\u6570\u636e\u8fc1\u79fb\u5de5\u4f5c\u3002\u4ed6\u4e3a\u89e3\u51b3\u4e86 node \u5728 window \u5e73\u53f0\u4e0a\u8fd0\u884c\u7684\u95ee\u9898\u3002Bert Belder \u662f libuv \u7684\u4f5c\u8005\uff0clibuv \u662f libev \u7684\u96c6\u6210\u8005\uff0c\u5b83\u89e3\u51b3\u4e86\u4e0d\u540c\u5e73\u53f0\u5f02\u6b65 IO \u6a21\u578b\u7684\u5c01\u88c5\u548c\u5b9e\u73b0\u3002node 0.4 \u4e4b\u524d libev \uff0c\u4e00\u4e2a select \u7684\u5305\u88c5\uff0c\u5f88\u8001\u800c\u4e14\u901f\u5ea6\u4e00\u822c\uff0c\u53ea\u652f\u6301 macOS \u548c Linux \uff0c\u8fd8\u4e0d\u652f\u6301 window \u3002

\n

\u5728\u65e9\u671f\u7684\u5f00\u53d1\u8fc7\u7a0b\u4e2d ry \u901a\u5e38\u4f1a\u5f15\u5165\u4e86\u7834\u574f\u6027\u53d8\u66f4\uff0c\u6bd4\u5982\uff1av0.0.3 \u4e2d\u628a sys \u6a21\u5757\u66f4\u540d\u4e3a util \u3002\u7136\u540e\u5927\u5bb6\u90fd\u60ca\u614c\u5931\u63aa\u4e86\u3002

\n

npm \u662f\u968f\u7740 node 0.0.8 \u7248\u672c\u540c\u65f6\u53d1\u5e03\u7684\uff0c\u4f46\u662f\u4e0b\u4e00\u4e2a node \u7248\u672c\u4e0a\u5c31\u6ca1\u6cd5\u7528\u4e86\u3002\u6240\u4ee5\u793e\u533a\u90fd\u60f3\u8981\u77e5\u9053 node \u7b2c\u4e00\u4e2a\u7a33\u5b9a\u7248\u672c\u4ec0\u4e48\u65f6\u5019\u53d1\u5e03\u7684\u65f6\u5019\u3002ry \u8bf4 1.0 \u7248\u672c\u8fd8\u6ca1\u6709\u5b8c\u6574\u7684\u8def\u7ebf\u56fe\uff0c\u56e0\u4e3a\u8fd9\u662f\u4e00\u4e2a\u5f88\u9065\u8fdc\u7684\u7248\u672c\uff0c\u76ee\u524d\u8fd8\u662f\u4e13\u6ce8\u4e8e 0.0.6 \u7248\u672c\uff0c\u9700\u8981\u91cd\u65b0\u8bbe\u8ba1\u7ba1\u9053\uff0c\u7136\u540e\u518d\u91cd\u65b0\u5ba1\u89c6\u8fd9\u4e2a\u95ee\u9898\u3002

\n

\u5de5\u4f5c\u4e86 1 \u5e74\u540e\uff0cjoyent \u60f3\u4ece ry \u624b\u91cc\u4e70\u4e0b Node.js \u8fd9\u4e2a\u9879\u76ee\u3002ry \u8bf4\u4ed6\u8fd8\u4e0d\u786e\u5b9a joyent \u4ece\u4ed6\u624b\u4e2d\u4e70\u4e0b\u4e00\u4e2a\u5f00\u6e90\u9879\u76ee\u662f\u597d\u4e8b\u8fd8\u662f\u574f\u4e8b\u3002\u5f53\u7136 ry \u77e5\u9053 joyent \u7684\u76ee\u7684\u7684\uff1ajoyent \u662f\u60f3\u7ba1\u7406\u8fd9\u4e2a\u9879\u76ee\uff0c\u62e5\u6709\u5546\u6807\u3001\u7f51\u7ad9\u5e76\u4e14\u5229\u7528\u8fd9\u4e2a\u6765\u63a8\u5e7f\u4ed6\u4eec\u7684\u516c\u53f8\u3002ry \u540c\u610f\u4e86\u8fd9\u7b14\u4ea4\u6613\uff0c\u56e0\u4e3a\u4ed6\u5f53\u65f6\u5e76\u6ca1\u6709\u56e0\u6b64\u5931\u53bb\u4e9b\u4ec0\u4e48\uff0c\u6240\u4ee5\u4ed6\u611f\u89c9\u5f88\u597d\u3002\u793e\u533a\u5f53\u7136\u4f1a\u6709\u5f88\u591a\u8d28\u7591\uff0c\u5927\u5bb6\u4f1a\u89c9\u5f97\u8fd9\u5bf9 Node \u610f\u5473\u7740\uff0c\u5982\u679c joyent \u53d8\u574f\u4f1a\u600e\u4e48\u6837\uff1f\u4f46\u662f\u56e0\u4e3a ry \u548c joyent \u8fbe\u6210\u7684\u534f\u8bae\u662f node.js \u8fd8\u662f\u4f1a\u4ee5 MIT \u8bb8\u53ef\u6765\u53d1\u5e03\u6e90\u4ee3\u7801\uff0c\u5b9e\u9645\u4e0a joyent \u4e70\u7684\u53ea\u662f\u4e00\u4e2a\u540d\u5b57\u3002

\n

\u540e\u6765 Node.js \u7684\u8fd0\u8425\u548c\u4e00\u4e9b\u7ba1\u7406\u4e0a\u7684\u5de5\u4f5c joyent \u4f1a\u51b3\u5b9a\uff0cry \u628a\u7ba1\u7406\u4e0a\u7684\u4e00\u4e9b\u4e8b\u52a1\u4ea4\u7ed9\u4e86 Isaac \u5e76\u9010\u6e10\u9000\u51fa\u4e86 Node.js \uff0c\u540e\u6765 Isaac \u5bf9\u4e8e\u8fd0\u8425 Node.js \u7684\u5de5\u4f5c\u611f\u89c9\u5230\u65e0\u804a\u548c\u538c\u5026\uff0c\u5de5\u4f5c\u4ea4\u7ed9 TJ \u540e\u9000\u51fa\u3002

\n

\u6700\u540e joyent \u4e5f\u4e0d\u600e\u4e48\u628a\u7cbe\u529b\u6295\u5165\u5230 node.js \u4e2d\uff0cnode \u4ee3\u7801\u4ed3\u5e93\u7684\u8fed\u4ee3\u660e\u663e\u51cf\u5c11\u3002\u66f4\u65b0\u660e\u663e\u653e\u7f13\uff0c\u793e\u533a\u89c9\u5f97 Joyent \u5bf9\u65b0\u529f\u80fd\uff08\u6bd4\u5982 ES6 \u7279\u6027\u3001\u6a21\u5757\u7cfb\u7edf\u3001\u534f\u7a0b\u65b9\u6848\uff09\u7684\u63a8\u8fdb\u8fc7\u4e8e\u4fdd\u5b88\uff0c\u7ef4\u62a4\u6548\u7387\u4e0d\u9ad8\u3002

\n

Node Forward, \u8ba8\u8bba node \u672a\u6765\u7684\u53d1\u5c55\uff0c\u6838\u5fc3\u7ef4\u62a4\u8005\u5411 joyent \u63d0\u51fa\u5f00\u653e\u5f0f\u7684\u7ba1\u7406\u3002

\n

mikreal \u5206\u53c9 node.js \u8d77\u540d iojs \u3002

\n

joyent \u6362 CEO Scott Hammond \u4e0e\u6838\u5fc3\u5f00\u53d1\u8005\u6c9f\u901a\u3002

\n

\u4e09\u4e2a\u6708\u540e

\n

\u53cc\u65b9\u5c31 Node.js \u9879\u76ee\u6cbb\u7406\u6a21\u5f0f\u8fbe\u6210\u4e00\u81f4\uff1a\u6280\u672f\u65b9\u5411\u548c\u6280\u672f\u51b3\u7b56\u771f\u6b63\u7531\u793e\u533a\u9a71\u52a8\u7684\uff0c\u4ece\u800c\u786e\u4fdd\u9879\u76ee\u5728\u771f\u6b63\u7684\u5171\u8bc6\u6a21\u5f0f\u4e0b\u8fd0\u884c\uff0c\u800c\u4e0d\u4ee3\u8868\u4efb\u4f55\u7ec4\u7ec7\u7279\u6b8a\u5229\u76ca\u7684\u6a21\u5f0f\u3002io.js \u6210\u4e86\u4e00\u4e2a\u91cd\u5927\u7684\u8b66\u544a\uff0c\u8ba9 joyent \u610f\u8bc6\u5230\u4ed6\u4eec\u5728 node \u4e2d\u62e5\u6709\u7684\u4e1c\u897f\u5b9e\u9645\u4e0a\u5371\u9669\u4e4b\u4e2d\u3002

\n

\u540c\u65f6\u5efa\u7acb Node.js Foundion \u3002joyent \u8bf4\u4e3a\u4e86\u6211\u4eec\u7684\u5229\u76ca\uff0c\u6211\u4eec\u4e0d\u9700\u8981\u6210\u4e3a Node \u7684\u7ba1\u7406\u8005\uff0c\u4f46\u662f\u6211\u4eec\u9700\u8981 Node \u4f5c\u4e3a\u4e00\u4e2a\u7edf\u4e00\u7684\u9879\u76ee

\n

node 4.0 \u53d1\u5e03\u5408\u5e76\u4e86 io.js

\n

2019 \u5e74 Node.js Foundation \u548c JS Foundation \u5408\u5e76\u6210 OpenJS Foundation \u3002

\n

\u5728\u8fd9\u4e4b\u540e ry \u6de1\u51fa Node.js \uff0c\u4ed6\u82b1\u4e86\u51e0\u5e74\u65f6\u95f4\u5728\u5176\u5b83\u5174\u8da3\u4e0a\uff1a\u673a\u5668\u5b66\u4e60\uff0c\u5206\u5e03\u5f0f\u7cfb\u7edf\uff0c\u51e0\u4f55\uff0c\u6444\u5f71\u7b49\u3002

\n

2018 \u5e74 JSConf EU \u56de\u5f52\uff0c\u53d1\u8868\u6f14\u8bb2 10 Things I Regret About Node.js\uff0c\u6b64\u65f6\u7684 ry \u770b\u8d77\u6765\u66f4\u6f47\u6d12\u3001\u65f6\u5c1a\u3002\u751a\u81f3\u4e0d\u50cf\u662f\u4e00\u4e2a\u4e0a\u6280\u672f\u5206\u4eab\u4f1a\u7684\u7a0b\u5e8f\u5458\u7684\u5f62\u8c61\uff0c\u867d\u7136\u8fd8\u662f\u5f88\u7d27\u5f20\u3002

\n

\"ry-deno.png\"

\n

\u5728\u4ed6\u6de1\u51fa\u7684\u8fd9\u6bb5\u65f6\u95f4\uff0c\u524d\u7aef\u6216\u8005\u8bf4 Node.js \u793e\u533a\u5df2\u7ecf\u6709\u5f88\u5927\u53d8\u5316\u4e86\u3002Node.js \u4f3c\u4e4e\u4e5f\u6709\u4e00\u4e9b\u74f6\u9888\u548c\u95ee\u9898\u3002

\n

\u4f46\u5728\u8fd9\u4e2a\u89c6\u9891\u4e2d\u4ed6\u5766\u7387\u5730\u8bb2\u51fa\u4e86\u81ea\u5df1\u5728 Node.js \u4e2d\u7684\u4e00\u4e9b\u8bbe\u8ba1\u300c\u7f3a\u9677\u300d\uff1a

\n\n

\u53ef\u4ee5\u770b\u5230 ry \u603b\u7ed3\u7684\u8fd9\u4e9b\u95ee\u9898\u975e\u5e38\u7cbe\u51c6\u7684\u6233\u5230\u4e86\u5f53\u65f6 Node.js \u7684\u4e00\u4e9b\u6838\u5fc3\u95ee\u9898\u3002\u6211\u60f3\u7ecf\u5386\u8fc7\u90a3\u4e2a\u65f6\u4ee3\u7684\u7a0b\u5e8f\u5458\u4e00\u5b9a\u4f1a\u8bb0\u5f97\uff1acallback hell, node_modules, node-sass, gyp, fsevent...

\n

\u6709\u610f\u601d\u7684\u662f\u5b9e\u9645\u4e0a\u5728 Node.js \u51fa\u73b0\u4e4b\u95f4 Javascript \u56de\u8c03\u5730\u72f1\u5e76\u6ca1\u6709\u90a3\u4e48\u81ed\u540d\u662d\u8457\uff0c\u56e0\u4e3a Node.js \u51fa\u73b0\u540e\u4f7f\u7528\u4e86\u5f02\u6b65 IO \u7684\u6a21\u578b\uff0c\u521a\u597d\u56de\u8c03\u51fd\u6570\u7684\u6a21\u5f0f\u53ef\u4ee5\u548c\u5f02\u6b65 IO \u5f88\u597d\u7684\u878d\u5408\uff0c\u5199\u8d77\u6765\u5f88\u81ea\u7136\u3002\u4f46\u662f\u4f7f\u7528\u7684\u592a\u591a\u4e86\u5c31\u4f1a\u53e6\u4eba\u611f\u5230\u4e0d\u9002\uff1a

\n

callback hell

\n
doSomething(function(result1) {\n doSomethingElse(result1, function(result2) {\n doAnotherThing(result2, function(result3) {\n doFinalThing(result3, function(result4) {\n console.log('Done:', result4);\n });\n });\n });\n});\n
\n

Promise

\n
doSomething()\n .then(result1 => doSomethingElse(result1))\n .then(result2 => doAnotherThing(result2))\n .then(result3 => doFinalThing(result3))\n .then(result4 => console.log('Done:', result4))\n .catch(err => console.error(err));\n
\n

async/await

\n
async function main() {\n try {\n const result1 = await doSomething();\n const result2 = await doSomethingElse(result1);\n const result3 = await doAnotherThing(result2);\n const result4 = await doFinalThing(result3);\n console.log('Done:', result4);\n } catch (err) {\n console.error(err);\n }\n}\nmain();\n
\n

\u4e3a\u4e86\u89e3\u51b3\u8fd9\u4e9b\u95ee\u9898\uff0c\u4ed6\u53c8\u53d1\u660e\u4e86\u4e00\u4e2a\u65b0\u4e1c\u897f\uff1aDeno - \u4e00\u4e2a\u57fa\u4e8e V8 \u7684\u5b89\u5168 TypeScript \u8fd0\u884c\u65f6\u3002

\n

\"ry-deno-intro.png\"

\n

deno \u7684\u51fa\u73b0\u53ef\u4ee5\u8bf4\u89e3\u51b3\u4e86 Node.js \u6240\u6709\u8bbe\u8ba1\u4e0a\u7684\u91cd\u5927\u7f3a\u9677\u95ee\u9898\uff0c\u5e76\u4e14\u5f15\u7528\u4e86 TypeScript \uff0c\u8fd9\u4f7f\u5f97\u4f7f\u7528 Javascript \u7f16\u5199\u4e25\u8083\u7684\u7a0b\u5e8f\u3001\u7cfb\u7edf\u6210\u4e3a\u53ef\u80fd\u3002

\n

\u503c\u5f97\u6ce8\u610f\u7684\u662f\uff0c\u65e9\u671f\u7684 deno \u5e95\u5c42\u662f Go \u5b9e\u73b0\u7684\uff0c\u5728\u540e\u6765\u7684\u8fed\u4ee3\u4e2d\u6362\u6210\u4e86 Rust \uff0c\u5176\u4e2d\u4e00\u4e2a\u91cd\u8981\u7684\u539f\u56e0\u662f\uff1aJavascript \u662f\u4e00\u95e8\u9ad8\u7ea7\u7a0b\u5e8f\u8bed\u8a00\uff0c\u662f\u6709\u5783\u573e\u56de\u6536\u7684\u3002\u800c Go \u4e5f\u4e00\u6837\uff0c\u5982\u679c\u7528 Go \u5b9e\u73b0\u90a3 deno \u7684\u8fd0\u884c\u65f6\u5c31\u4f1a\u6709\u4e24\u4e2a\u5783\u573e\u56de\u6536\u5668\u3002ry \u5728\u540e\u6765\u7684\u6f14\u8bb2\u4e2d\u8bf4\uff1a\u6709\u4e24\u4e2a\u5783\u573e\u56de\u6536\u5668\u90a3\u6837\u4e0d\u5bf9\u3002\u867d\u7136\u4e0d\u662f\u4e0d\u53ef\u4ee5\uff0c\u4f46\u662f\u51fa\u4e8e\u7a0b\u5e8f\u5458\u7684\u76f4\u89c9\u4e24\u4e2a\u5783\u573e\u56de\u6536\u5668\u662f\u4e0d\u5bf9\u7684\u3002

\n

2021-4 \u6210\u7acb deno \u516c\u53f8

\n

2022-6 Deno \u5b8c\u6210\u4e86\u7ea2\u6749\u8d44\u672c\u9886\u6295\u7684 2100 \u4e07\u7f8e\u5143 A \u8f6e\u878d\u8d44\uff0c\u603b\u878d\u8d44\u989d\u8fbe\u5230 2600 \u4e07\u7f8e\u5143\uff0c\u76ee\u6807\u662f\u5f00\u53d1\u4e00\u6b3e\u5546\u4e1a\u4ea7\u54c1 Deno Deploy\u3002

\n

\u6211\u7684\u535a\u5ba2\u4e5f\u6258\u7ba1\u5728 deno deploy \u4e0a\uff0c\u4ee5\u524d\u7528\u8fc7 github pages, hugo, hexo \u7b49\uff0c\u4f46\u662f\u591a\u5c11\u8fd8\u662f\u6709\u70b9\u95ee\u9898\uff0c\u521a\u597d\u56e0\u4e3a\u81ea\u5df1\u5bf9 Javascript \u719f\u6089\u6240\u4ee5\u4e00\u76f4\u7528\u514d\u8d39\u7248\u7684 deno deploy \u3002

\n

\u2014\u2014

\n

\u8fd9\u5c31\u662f ry \u5230\u76ee\u524d\u4e3a\u6b62\u505a\u5230\u7684\u4e8b\u60c5\uff0c\u5f53\u7136\u6545\u4e8b\u8fd8\u5728\u7ee7\u7eed\u3002\u6beb\u65e0\u7591\u95ee ry \u662f\u4e00\u4e2a\u6210\u529f\u7684\u7a0b\u5e8f\u5458\u3001\u5de5\u7a0b\u5e08\u3001\u8001\u677f\u3001Node.js \u793e\u533a\u7684\u7cbe\u795e\u9886\u8896\u3002\u6211\u60f3\u4ece\u6211\u81ea\u5df1\u7684\u89c6\u89d2\u603b\u7ed3\u51e0\u4e2a\u5173\u4e8e\u4ed6\u7684\u95ee\u9898\uff0c\u8fd9\u4f1a\u5bf9\u6211\u4eec\u7684\u5de5\u4f5c\u3001\u751f\u6d3b\u6709\u6240\u542f\u53d1\u3002

\n

\u5728\u8fd9\u4e4b\u524d\u6211\u60f3\u6709\u51e0\u4e2a\u65f6\u95f4\u70b9\u5728\u6280\u672f\u9886\u57df\u662f\u975e\u5e38\u91cd\u8981\u7684\uff1a

\n
    \n
  1. Linux 2.5.44 \u5185\u6838\u53d1\u5e03\u4e8e 2003 \u5e74 6 \u6708 26 \u65e5\uff0c\u5f15\u5165 epoll \u5927\u6982 22 \u5e74\u524d
  2. \n
  3. Nginx \u53d1\u5e03\u4e8e 2004 \u5e74 10 \u6708 4 \u65e5\uff0c\u5927\u6982 21 \u5e74\u524d
  4. \n
  5. V8 Javascript \u5f15\u64ce\u53d1\u5e03\u4e8e 2008 \u5e74 9 \u6708 2 \u65e5\uff0c\u5927\u6982 17 \u5e74\u524d
  6. \n
  7. Node.js \u9996\u6b21\u53d1\u5e03\u4e8e 2009 \u5e74 5 \u6708 28 \u65e5\uff0c \u5927\u6982 16 \u5e74
  8. \n
\n

epoll \u5728 Linux \u5185\u6838\u4e2d\u4e4b\u524d\uff0c\u5927\u90e8\u5206\u7f51\u7ad9\u4f7f\u7528\u7684\u670d\u52a1\u5668\u8fd8\u662f apache \u3002apache \u670d\u52a1\u5668\u7684\u6a21\u578b\u662f\u591a\u7ebf\u7a0b\u7684\uff0c\u4e00\u8bf7\u6c42\u4e00\u7ebf\u7a0b\uff0c\u663e\u7136\u8fd9\u662f\u65e0\u6cd5\u5e94\u5bf9\u5927\u91cf\u5e76\u53d1\u8bbf\u95ee\u7684\u3002\u56e0\u4e3a\u542f\u52a8\u4e00\u4e2a\u7ebf\u7a0b\u4f1a\u6709\u5f88\u591a\u5f00\u9500\uff0c\u5047\u5982\uff1a\u542f\u52a8\u4e00\u4e2a\u7ebf\u7a0b\u9700\u8981 5MB \u7684\u5185\u5b58\uff0c\u90a3\u4e48 1G \u5185\u5b58\u7684\u673a\u5668\u4e0a\u5c31\u6700\u591a\u53ea\u80fd\u5f00 200 \u591a\u4e2a\u7ebf\u7a0b\uff0c\u4e5f\u5c31\u610f\u5473\u7740\u4e00\u53f0 1G \u5185\u5b58\u7684\u7535\u8111\u53ea\u80fd\u670d\u52a1 200 \u4e2a HTTP \u8fde\u63a5\uff08\u7528\u6237\uff09\u3002

\n

\u4f46\u662f\u968f\u7740\u4e92\u8054\u7f51\u7684\u53d1\u5c55\uff0c\u5927\u5bb6\u5728\u7f51\u4e0a\u7684\u6d3b\u52a8\u8d8a\u6765\u8d8a\u9891\u7e41\uff0c\u8fd9\u624d\u51fa\u73b0\u4e86\u5927\u91cf\u7684\u9ad8\u6d41\u91cf\u7f51\u7ad9\uff0c\u793e\u4ea4\u5a92\u4f53\u3001BBS \u3001\u641c\u7d22\u5f15\u64ce\u3001\u535a\u5ba2\u3001\u4e2a\u4eba\u7f51\u7ad9\u7b49\u7b49\u3002\u4e00\u65f6\u4e4b\u95f4\u7f51\u7edc\u6d41\u884c\u8d77\u6765\uff0c\u5927\u5bb6\u5728\u4e0a\u7f51\u7684\u65f6\u5019\u8d8a\u6765\u8d8a\u591a\u3002

\n

Nginx \u5c31\u5e94\u8fd0\u800c\u751f\u4e86\uff0c\u4ed6\u629b\u5f03\u4e86 apache \u7ebf\u7a0b\u9a71\u52a8\u6a21\u5f0f\uff0c\u4f7f\u7528\u4e8b\u4ef6\u9a71\u52a8\uff0c\u5f02\u6b65\u975e\u963b\u585e\u6a21\u5f0f\u3002Linux \u4e0b\u4f7f\u7528 epoll \u5b9e\u73b0\u5f02\u6b65 IO \u3002Nginx \u8bbe\u8ba1\u4e4b\u521d\u5c31\u89e3\u51b3\u4e86 C10K \u95ee\u9898\u3002\u5bf9\u4e8e \u9759\u6001\u6587\u4ef6\u670d\u52a1\u3001\u53cd\u5411\u4ee3\u7406\u3001\u8d1f\u8f7d\u5747\u8861\u5e94\u7528\u573a\u666f\u5c55\u793a\u51fa\u4e86\u6781\u9ad8\u7684\u6027\u80fd\u3002

\n

\u6211\u7b2c\u4e00\u6b21\u4f7f\u7528 Nginx \u7684\u53cd\u5411\u4ee3\u7406\u7684\u65f6\u5019\uff0c\u611f\u89c9\u5c31\u662f\uff1a\u54c7\uff0c\u8fd9\u662f\u4ec0\u4e48\u9b54\u6cd5\uff0c\u592a\u795e\u5947\u4e86\u3002\u53ea\u9700\u8981\u4e00\u884c\u914d\u7f6e\u5c31\u53ef\u4ee5\u8ba9 A \u7f51\u7ad9\u5c55\u793a B \u7f51\u7ad9\u7684\u5185\u5bb9\u3002

\n

\u6ce8\u610f\u5728\u8fd9\u4e2a\u65f6\u95f4\u8282\u70b9\uff0c\u5927\u6982 2004 \u5e74\u7684\u65f6\u5019\u4e0d\u6ca1\u6709\u4efb\u4f55\u7f16\u7a0b\u8bed\u5177\u5907\u5f02\u6b65\u7f16\u7a0b\u6a21\u578b\u7684\u9ed8\u8ba4\u8303\u5f0f\u3002\u5f53\u65f6\u5f02\u6b65\u7f16\u7a0b\u6982\u5ff5\u662f\u5f88\u65e9\u5c31\u6709\u4e86\u3002\u6211\u8fd9\u91cc\u8bb2\u7684\u9ed8\u8ba4\u8303\u5f0f\u53ef\u4ee5\u7406\u89e3\u6210\u6307\u5b9a\u7f16\u7a0b\u8bed\u8a00\u4e2d\u7684\u7f16\u7a0b\u98ce\u683c\u6216\u8005\u8bf4\u8bed\u8a00\u5185\u6838\u3002\u6bd4\u5982\uff1aJava \u7684 OOP \uff0cHaskell \u7684 FP \uff0c\u73b0\u5728 Javascript \u4e2d\u7684 Promise/async/await \u3002

\n

\u663e\u7136 ry \u77e5\u9053 Nginx \u7684\u6838\u5fc3\u539f\u7406\uff0c\u4ed6\u662f\u60f3\u628a\u5f02\u6b65 IO \u8fd9\u79cd\u6a21\u578b\u690d\u5165\u5230\u67d0\u4e2a\u7f16\u7a0b\u8bed\u8a00\u4e2d\u53bb\uff0c\u4f60\u53ef\u4ee5\u60f3\u8c61\u7684\u5230\u8fd9\u4e2a\u60f3\u6cd5\u7684\u5a01\u529b\u6709\u591a\u5927\u5417\uff1f Nginx \u662f\u4e00\u4e2a\u5e94\u7528\u5c42\u8f6f\u4ef6\u5f15\u5165\u5f02\u6b65 IO \u540e\u6709\u8fd9\u4e48\u5927\u7684\u6027\u80fd\u63d0\u5347\uff0c\u5982\u679c\u628a\u8fd9\u4e2a\u6a21\u578b\u5f15\u5165\u5230\u4e00\u4e2a\u7f16\u7a0b\u8bed\u8a00\u4e2d\uff0c\u90a3\u6574\u4e2a\u7f16\u7a0b\u8bed\u8a00\u90fd\u662f\u57fa\u4e8e\u5f02\u6b65 IO \u7684\uff0c\u6027\u80fd\u4f1a\u6bd4\u540c\u6b65\u7684\u9ad8\u51fa\u5f88\u591a\u500d\uff0c\u4eba\u4eec\u53ef\u4ee5\u8f7b\u6613\u7684\u7f16\u5199\u51fa\u9ad8\u6548\u7684\u7a0b\u5e8f\u3002

\n

\u5c31\u50cf\u524d\u6587\u4e2d\u8bb2\u5230\u7684\uff0cry \u4e5f\u7814\u7a76\u8fc7\u5176\u5b83\u7f16\u7a0b\u8bed\u8a00\uff0c\u6ca1\u6709\u5408\u9002\u7684\u3002\u4f46\u662f\u65e0\u610f\u4e2d\u53d1\u73b0 Javascript \u5f88\u5408\u9002\u3002

\n

V8 \u7684\u51fa\u73b0\u8ba9 chrome \u6d4f\u89c8\u5668\u5728 2008\u20132015 \u5e74\u671f\u95f4\uff0c\u5e02\u573a\u5360\u7528\u7387\u4ece 0 \u5230\u4e86 53%\uff0c\u8ba9\u6574\u4e2a WEB \u52a0\u901f\uff0c\u4e5f\u8ba9 PC \u65f6\u4ee3\u5230\u8fbe\u4e86\u53d1\u5c55\u7684\u9876\u5cf0\u3002\u90a3\u6bb5\u65f6\u95f4\u6bcf\u5e74\u90fd\u4f1a\u51fa\u73b0\u65b0\u7684\u6d41\u884c\u7684\u4e1c\u897f\u3002\u7f51\u7edc\u804a\u5929\uff0c\u8bba\u575b BBS \uff0c\u4e2a\u4eba\u535a\u5ba2\uff0c\u5fae\u535a\uff0c\u56e2\u8d2d\uff0c\u7535\u5546\u3002\u6574\u4e2a\u4e92\u8054\u7f51\u662f\u4e00\u7247\u671d\u6c14\u84ec\u52c3\u7684\u6837\u5b50\u3002

\n

\u6211\u81ea\u5df1\u5199\u535a\u5ba2\u4e5f\u662f\u5f53\u65f6\u53d7\u5230\u4e86\u97e9\u5bd2\u3001\u5f90\u9759\u857e\u65b0\u6d6a\u535a\u5ba2\u7684\u6392\u540d\u7684\u70ed\u5ea6\u5f71\u54cd\u3002

\n

\u53ef\u4ee5\u60f3\u8c61\u5f53\u65f6\u5927\u5bb6\u5bf9\u6d4f\u89c8\u5668\u4e00\u79cd\u4ec0\u4e48\u6837\u7684\u9700\u6c42\uff0c\u5927\u5bb6\u4f3c\u4e4e\u611f\u89c9\u4e0d\u592a\u5230\u6d4f\u89c8\u5668\u6709\u591a\u91cd\u8981\uff0c\u4f46\u662f\u5bf9\u4e8e Javascript \u6765\u8bb2\u5374\u662f\u6697\u6d41\u6d8c\u52a8\u3002\u5f7c\u65f6\u7684\u6d4f\u89c8\u5668\u53ef\u4ee5\u8bf4\u662f\u4e07\u82b1\u9f50\u653e\uff1a

\n\n

\u6700\u7ec8\uff0c\u6280\u672f\u4e0a\u5f02\u6b65 IO \u6a21\u578b\u88ab\u9a8c\u8bc1\u4e86\u6b63\u786e\u6027\uff0cV8 \u7684\u51fa\u73b0\u4e5f\u9010\u6b65\u628a Javascript \u62c9\u5411\u4e86\u6b63\u7ecf\u4e25\u8083\u7684\u7f16\u7a0b\u8bed\u8a00\u884c\u5217\uff08\u5f53\u7136\u76ee\u524d\u770b\u6765\u5f88\u591a\u5730\u65b9\u8fd8\u4e0d\u591f\u4e25\u8083\uff09\u3002\u7136\u540e Node.js \u7684\u51fa\u73b0\u5c31\u663e\u5f97\u5f88\u6c34\u5230\u6e20\u6210\u3002

\n

\u5f53\u7136\u5982\u679c\u53ea\u770b\u5230\u8fd9\u4e9b\u6cdb\u6cdb\u7684\u8d8b\u52bf\u3001\u82d7\u5934\u5176\u5b9e\u5e76\u4e0d\u80fd\u5f88\u5ba2\u89c2\u7684\u89e3\u91ca\u6700\u7ec8\u4e3a\u4ec0\u4e48\u662f Javascript \u800c\u4e0d\u662f\u5176\u5b83\u8bed\u8a00\uff0c\u56e0\u4e3a\u5728\u6211\u7684\u804c\u4e1a\u751f\u6daf\u4e2d\u4ece\u4e8b Javascript \u7f16\u7a0b\u5360\u5927\u90e8\u5206\u65f6\u95f4\uff0c\u6240\u4ee5\u6211\u8fd8\u662f\u60f3\u4ece\u7f16\u7a0b\u8bed\u8a00\u7684\u89d2\u5ea6\u6765\u603b\u7ed3\u4e0b\u4e3a\u4ec0\u4e48 Javascript \u6bd4\u8f83\u5408\u9002\u7684\u539f\u56e0\u3002

\n

\u4e3b\u8981\u539f\u56e0\u6709\u4e09\u4e2a\uff1a

\n

\u7b2c\u4e00\uff1aJavascript \u8fd8\u5f88\u5e74\u8f7b\uff08\u5f88\u521d\u7ea7\uff09

\n

\u9009\u62e9 Javascript \u4e0d\u662f\u56e0\u4e3a Javascript \u8fd9\u95e8\u8bed\u8a00\u597d\uff0c\u800c\u662f\u56e0\u4e3a Javascript \u8fd9\u95e8\u7f16\u7a0b\u8bed\u8a00\u8fd8\u5f88\u521d\u7ea7\uff0c\u5f53\u65f6\u7684 JS \u8fd8\u5904\u4e8e\u811a\u672c\u8bed\u8a00\u7684\u8303\u7574\uff0c\u4eba\u4eec\u7528\u5b83\u6765\u7f16\u7a0b\u57fa\u672c\u4e0a\u5f88\u591a\u65f6\u5019\u662f\u8c03\u7528\u6d4f\u89c8\u5668\u8fd9\u4e2a\u5bbf\u4e3b\u73af\u5883\u63d0\u4f9b\u7684\u4e00\u4e9b API \uff0c\u6bd4\u5982\uff1aDOM/BOM/XHR \u7b49\u3002\u4f46\u662f\u4e25\u8083\u7684\u8bb2\u5f53\u65f6\u7684 Javascript \u8fd8\u53ea\u662f\u4e00\u4e2a\u73a9\u5177\u811a\u672c\u8bed\u8a00\u3002

\n

\u7b2c\u4e8c\uff1aJavascript \u8bed\u8a00\u7279\u6027\u4e30\u5bcc

\n

Javascript \u8bed\u8a00\u662f\u4e00\u95e8\u770b\u8d77\u6765\u5565\u529f\u80fd\u90fd\u6709\u7684\u8bed\u8a00\u3002\u6211\u4eec\u53ef\u4ee5\u770b\u770b\u300a Javascript \u6743\u5a01\u6307\u5357\u300b\u4e2d\u7684\u4e00\u6bb5\u5173\u4e8e Javascript \u7684\u4ecb\u7ecd

\n
\n

Javascript \u662f\u9762\u5411 web \u7684\u7f16\u7a0b\u8bed\u8a00\uff0c\u662f\u4e00\u95e8\u00a0\u9ad8\u9636\u7684\uff08 high-level \uff09\u3001\u00a0\u52a8\u6001\u7684\uff08 dynamic \uff09\u3001\u00a0\u5f31\u7c7b\u578b\u7684\uff08 untyped \uff09\u00a0\u89e3\u91ca\u578b\uff08 interpreted \uff09\u7f16\u7a0b\u8bed\u8a00\uff0c\u9002\u5408\u9762\u5411\u5bf9\u8c61\uff08 oop \uff09\u548c\u51fd\u6570\u5f0f\u7684\uff08 functional \uff09\u7f16\u7a0b\u98ce\u683c\u3002Javascript \u8bed\u6cd5\u6e90\u81ea Java \u548c C \uff0c\u4e00\u7b49\u51fd\u6570\uff08 first-class function \uff09\u6765\u81ea\u4e8e Scheme \uff0c\u5b83\u7684\u57fa\u4e8e\u539f\u578b\u7ee7\u627f\u6765\u81ea\u4e8e Self

\n
\n

\u53ef\u4ee5\u770b\u51fa\u6765 Javascript \u5565\u7279\u6027\u90fd\u6709\uff0c\u4f46\u5b9e\u9645\u4e0a\u5565\u7279\u6027\u90fd\u4e0d\u597d\u7528\u3002\u8fd9\u5c31\u7ed9 ry \u4e00\u4e2a\u9009\u62e9 Javascript \u7684\u7406\u7531\uff0c\u8fd9\u95e8\u7f16\u7a0b\u8bed\u8a00\u4e0a\u6ca1\u6709\u4ec0\u4e48\u7279\u522b\u597d\u7684\u4e1c\u897f\uff0c\u624d\u4e0d\u81f3\u4e8e\u5b83\u6709\u4e00\u4e9b\u9ed8\u8ba4\u7684\u8303\u5f0f\u800c\u5bfc\u81f4\u8bed\u8a00\u5c42\u9762\u5f15\u5165\u5f02\u6b65 IO \u4f1a\u4ea7\u751f\u5f88\u5927\u7684\u963b\u529b\u3002

\n

\u7b2c\u4e09\uff1aJavascript \u7684\u6838\u5fc3\uff0c\u5355\u7ebf\u7a0b\u4e8b\u4ef6\u9a71\u52a8

\n

\u8fd9\u4e2a\u662f Javascript \u8fd9\u79cd\u811a\u672c\u8bed\u8a00\u88ab\u8bbe\u8ba1\u4e4b\u521d\u5c31\u786e\u5b9a\u597d\u7684\uff0c\u56e0\u4e3a\u811a\u672c\u8bed\u8a00\u5c31\u662f\u7528\u6765\u5c4f\u853d\u5e95\u5c42\u590d\u6742\u6027\u7684\u3002\u4f60\u5f88\u96be\u60f3\u8c61\u5982\u679c Javascript \u5b9e\u73b0\u4e0a\u63d0\u4f9b\u591a\u7ebf\u7a0b\uff0c\u540c\u65f6\u53c8\u8dd1\u5728\u6d4f\u89c8\u5668\u91cc\u9762\u5b83\u4f1a\u628a\u6d4f\u89c8\u5668\u641e\u6210\u4ec0\u4e48\u9b3c\u6837\u5b50\u3002

\n

\u4e8b\u4ef6\u9a71\u52a8\u8fd9\u4e2a\u597d\u7406\u89e3\uff0c\u56e0\u4e3a Javascript \u88ab\u8bbe\u8ba1\u51fa\u6765\u5c31\u662f\u8981\u5904\u7406\u7528\u6237 UI \u754c\u9762\u4e0a\u7684\u4e8b\u4ef6\u7684\u3002\u6bd4\u5982\uff1a\u7528\u6237\u70b9\u51fb\u6309\u94ae\uff0c\u63d0\u4ea4\u8868\u5355\u3002

\n

\u5355\u7ebf\u7a0b\u4e8b\u4ef6\u9a71\u52a8\u8fd9\u4e00\u70b9\u53ef\u4ee5\u8bf4\u662f\u6280\u672f\u4e0a\u6700\u5408\u9002\u7684\u4e00\u70b9\uff0c\u56e0\u4e3a\u5f53 ry \u628a\u8fd9\u4e2a\u7406\u5ff5\u548c\u7f16\u7801\u65b9\u5f0f\u4e0e\u5f02\u6b65 IO \u96c6\u6210\u540e\uff0c\u7f16\u5199\u51fa\u6765\u7684\u4ee3\u7801\u975e\u5e38\u7b80\u5355\u800c\u4e14\u5bb9\u6613\u7406\u89e3\u3002

\n

\u6211\u4eec\u53ef\u4ee5\u770b\u770b Node.js \u5b98\u7f51\u4e0a\u4e00\u76f4\u5b58\u5728\u7684\u4ee3\u7801\u7247\u6bb5\uff0c\u5b9e\u73b0\u4e00\u4e2a\u7b80\u5355\u7684 HTTP \u670d\u52a1\u5668\uff1a

\n
import { createServer } from 'node:http';\n\nconst server = createServer((req, res) => {\n res.writeHead(200, { 'Content-Type': 'text/plain' });\n res.end('Hello World!\\n');\n});\n\nserver.listen(3000, '127.0.0.1', () => {\n console.log('Listening on 127.0.0.1:3000');\n});\n
\n

\u8fd9\u4e2a\u5b9e\u73b0\u5c31\u662f Node.js \u7684\u7cbe\u9ad3\uff1a\u5f02\u6b65\u975e\u963b\u585e IO \u30028 \u884c\u4ee3\u7801\u5b9e\u73b0\u4e00\u4e2a HTTP Server \uff0c\u6027\u80fd\u53ef\u4ee5\u548c Nginx \u5ab2\u7f8e\uff0c\u8fd9\u5df2\u7ecf\u8db3\u4ee5\u60ca\u8273\u6240\u6709\u4eba\u3002

\n

\u5f02\u6b65\u7f16\u7a0b\u7684\u8fd9\u79cd\u8303\u5f0f\u6b63\u5728\u690d\u5165\u5230 Javascript \u8fd9\u95e8\u8bed\u8a00\u4e2d\u3002\u81ea\u4ece Javascript \u6709\u4e86\u8fd9\u79cd\u6700\u4f73\u5b9e\u8df5\uff0c\u5f02\u6b65\u7f16\u7a0b\u7684\u6807\u51c6\u6a21\u578b\uff1aasync/await \u4e5f\u6162\u6162\u6e17\u900f\u5230\u4e86\u5176\u5b83\u7f16\u7a0b\u8bed\u8a00\u4e2d\uff0cPython/Rust \u90fd\u6709\u6240\u501f\u9274\u3002\u5f53\u7136\u5f02\u6b65\u7f16\u7a0b\u5728\u5176\u5b83\u7f16\u7a0b\u8bed\u8a00\u91cc\u9762\u4e5f\u6709\u5b9e\u73b0\uff0c\u4f46\u662f\u90fd\u6ca1\u6709\u5728 Javascript \u4e2d\u90a3\u4e48\u81ea\u7136\u3002

\n

\u6280\u672f\u754c\u603b\u6709\u4e00\u4e9b\u4eba\u9760\u81ea\u5df1\u7684\u672c\u9886\u8fc7\u4e0a\u4e86\u8863\u98df\u65e0\u5fe7\u7684\u751f\u6d3b\uff0c\u4f46\u662f\u8fc7\u4e0a\u8863\u98df\u65e0\u5fe7\u7684\u751f\u6d3b\u8fd9\u5e76\u6ca1\u6709\u4ec0\u4e48\u610f\u4e49\uff0c\u56e0\u4e3a\u4eba\u751f\u7684\u610f\u4e49\u603b\u662f\u5728\u4e8e\u521b\u9020\u4e00\u4e9b\u4e1c\u897f\u800c\u975e\u4eab\u53d7\u4e00\u4e9b\u7ed3\u679c\u3002\u6211\u60f3 ry \u662f\u8fd9\u6837\u7684\u4eba\uff0c\u8981\u4e0d\u7136\u4ed6\u4e5f\u4e0d\u4f1a\u5728\u5356\u4e86 Node.js \u5f97\u5230\u94b1\u4e4b\u540e\u8d70\u4e0a\u4e00\u6761\u7ed3\u675f\u81ea\u5df1\u4eba\u751f\u7684\u8def\u3002\u4e5f\u6b63\u5982\u4ed6\u5728\u81ea\u5df1\u4eba\u751f\u5173\u952e\u65f6\u523b\u505a\u51fa\u7684\u9009\u62e9\u4e00\u6837\uff1a\u505a\u770b\u5f97\u89c1\u7684\u3001\u80fd\u5b9e\u8df5\u7684\u4e8b\u60c5\u3002

\n

\u6211\u4e00\u76f4\u8ba4\u4e3a\u4efb\u4f55\u4e8b\u60c5\uff0c\u65b9\u5411\u5bf9\u4e86+\u4eba\u5bf9\u4e86\uff0c\u90a3\u7ed3\u679c\u5c31\u662f\u81ea\u7136\u800c\u7136\u7684\u6210\u529f\u3002\u5c31\u7b97\u4e0d\u6210\u529f\u4e5f\u6ca1\u6709\u4ec0\u4e48\u9057\u61be\u3002

\n

\u6240\u4ee5 Node.js \u6210\u529f\u4e86\uff0cNode.js \u7684\u6210\u529f\u5728\u4e8e\u5b83\u5f00\u521b\u4e86\u4e00\u4e2a\u65b0\u7684\u7eaa\u5143\uff0c\u4ed6\u4e3a\u539f\u6765\u5728\u524d\u7aef\u7684\u5f00\u53d1\u8005\u6253\u5f00\u4e86\u4e00\u6247\u95e8\uff0c\u8fd9\u91cc\u5927\u5bb6\u624d\u610f\u8bc6\u5230\uff1a\u539f\u6765\u524d\u7aef\u4e5f\u53ef\u4ee5\u5199\u540e\u7aef\uff0c\u4e5f\u53ef\u4ee5\u5199\u670d\u52a1\u7aef\uff0c\u524d\u7aef\u4e5f\u53ef\u4ee5\u5728\u66f4\u591a\u9886\u57df\u5b9e\u8df5\uff0c\u53ef\u4ee5\u548c\u66f4\u591a\u7684\u9886\u57df\u4e00\u8d77\u7ade\u4e89\u3002

\n

\u53c2\u8003\u8d44\u6599:

\n\n

\u535a\u5ba2\u539f\u6587

\n" }, { "author": { "url": "member/zhennann", "name": "zhennann", "avatar": "https://cdn.v2ex.com/avatar/97cf/ffd9/356142_large.png?m=1712331089" }, "url": "t/1162802", "title": "Vona ORM \u6587\u6863\u7ec8\u4e8e\u809d\u5b8c\u4e86\uff0c\u6b22\u8fce\u62cd\u7816", "id": "t/1162802", "date_published": "2025-09-30T01:53:41+00:00", "content_html": "

Vona ORM \u662f\u8239\u65b0\u7684 Node.js ORM \u5e93\u3002\u63d0\u4f9b\u7684\u591a\u79df\u6237\u80fd\u529b\u53ef\u4ee5\u540c\u65f6\u652f\u6301\u5171\u4eab\u6a21\u5f0f\u548c\u72ec\u7acb\u6a21\u5f0f\u3002\u9996\u521b DTO \u52a8\u6001\u63a8\u65ad\u4e0e\u751f\u6210\u80fd\u529b\uff0c\u89e3\u653e\u6211\u4eec\u7684\u53cc\u624b\uff0c\u663e\u8457\u63d0\u5347\u751f\u4ea7\u529b\u3002\u4e3a\u4ec0\u4e48\u6562\u8bf4\u662f\u9996\u521b\uff0c\u56e0\u4e3a Prisma \u548c Drizzle \u6ca1\u6709\u63d0\u4f9b\u6b64\u80fd\u529b\uff0cJava \u7cfb\u4ea6\u5982\u662f\u3002

\n

Vona ORM \u4e0d\u4ec5\u63d0\u4f9b\u57fa\u4e8e\u9759\u6001\u5173\u7cfb\u7684\u5173\u8054\u67e5\u8be2\uff0c\u8fd8\u63d0\u4f9b\u52a8\u6001\u5173\u7cfb\uff0c\u4ece\u800c\u9002\u5e94\u5927\u578b\u4e1a\u52a1\u7cfb\u7edf\u6240\u8981\u6c42\u7684\u7075\u6d3b\u6027\u548c\u6269\u5c55\u6027\u3002

\n

\u6b64\u6846\u67b6\u6240\u89c4\u5212\u7684\u80fd\u529b\u8fd8\u6709\u5f88\u591a\uff0c\u5c31\u4e0d\u518d\u8d58\u8ff0\uff0c\u4ee5\u514d\u5360\u7528\u5927\u5bb6\u5b9d\u8d35\u65f6\u95f4\u3002\u56e0\u4e3a\u529f\u80fd\u591a\uff0c\u6240\u4ee5\uff0c\u82b1\u4e86\u5927\u91cf\u65f6\u95f4\u7ec8\u4e8e\u628a\u6587\u6863\u809d\u51fa\u6765\u4e86\u3002\u611f\u5174\u8da3\u7684\uff0c\u53ef\u4ee5\u89c2\u6469\u4e00\u4e0b\uff0c\u6b22\u8fce\u62cd\u7816\u3002\ud83d\udc4f

\n

\u6587\u6863\u5730\u5740\uff1a https://vona.js.org/zh/guide/techniques/orm/introduction.html

\n" }, { "author": { "url": "member/Orangeee", "name": "Orangeee", "avatar": "https://cdn.v2ex.com/gravatar/0e522bb6f9e9b9fab7b47c3f138b3cba?s=73&d=retro" }, "url": "t/1158230", "title": "Node.js \u5b98\u7f51\u66f4\u65b0\u4e86", "id": "t/1158230", "date_published": "2025-09-10T03:13:42+00:00", "content_html": "https://nodejs.org/en
\u65b0\u7684\u5b98\u7f51\u611f\u89c9\u6bd4\u4e4b\u524d\u597d\u7528" }, { "author": { "url": "member/fx", "name": "fx", "avatar": "https://cdn.v2ex.com/avatar/44c2/821d/32939_large.png?m=1758687863" }, "url": "t/1154886", "title": "adonisjs \u6709\u6ca1\u6709\u73b0\u6210\u7684\u6ce8\u518c\u767b\u5f55\u5e93\uff1f", "id": "t/1154886", "date_published": "2025-08-25T16:02:02+00:00", "content_html": "

\u4ee5\u524d\u7528 rails \u7684\u65f6\u5019\uff0c\u53ef\u4ee5\u7528 https://github.com/heartcombo/devise\n\u8fd9\u79cd\u5e93\u5feb\u901f\u96c6\u6210\u6ce8\u518c\u8ba4\u8bc1\uff0c\u4e0d\u77e5\u9053\u6709\u6ca1\u6709\u4ec0\u4e48\u5e93\u9002\u7528\u4e8e adonisjs

\n" }, { "author": { "url": "member/libasten", "name": "libasten", "avatar": "https://cdn.v2ex.com/gravatar/f6d4baad62e4ee124d392af83650f37d?s=73&d=retro" }, "url": "t/1153964", "date_modified": "2025-08-22T00:02:37+00:00", "content_html": "\u662f\u56e0\u4e3a\u6b64\u524d\u5927\u524d\u7aef\u6982\u5ff5\u6162\u6162\u201c\u5165\u4fb5\u201d\u5230\u540e\u7aef\u7684\u5417\uff1f
\u8fd8\u662f\u5b83\u7684\u5185\u6838\u7b80\u4fbf\uff0c\u8d77\u624b\u5f88\u5feb\uff1f
\u7406\u8bba\u4e0a node \u7684 runtime \u6bd4 java dotnet \u90fd\u8f7b\u91cf\u5f88\u591a\uff1f\u6709\u70b9\u65e9\u5e74 php \u7684\u611f\u89c9\uff1f
\u6211\u770b\u5404\u79cd\u914d\u5957\u5de5\u5177\u6211\u770b\u66f4\u65b0\u98de\u5feb\uff0c\u5404\u79cd\u4e91\u670d\u52a1\u5382\u5546\u4e5f\u662f\u4e94\u82b1\u516b\u95e8\uff0c\u6bcf\u6b21\u770b\u8fd9\u7c7b\u5de5\u5177\u90fd\u611f\u89c9\u81ea\u5df1\u8131\u79bb\u65f6\u4ee3\u4e86\u3002
\u4f46\u662f\u6211\u8fd9\u4e24\u5929\u8bd5\u7740\u73a9\u73a9\uff0c\u611f\u89c9\u8981\u6df1\u5165\u7528\uff0c\u4e5f\u633a\u6298\u817e\u7684\uff0c\u548c\u524d\u7aef Javascript \u4e00\u6837\uff0c\u5404\u79cd\u7c7b\u5e93\u7684\u201c\u4f9d\u8d56\u9ed1\u6d1e\u201d\u633a\u5413\u4eba\u7684\uff0c\u6709\u65f6\u5019\u8981\u7528\u4e00\u4e2a\u65b0\u7684\u5de5\u5177\u5e93\uff0c\u63d0\u793a node \u7248\u672c\u4e0d\u652f\u6301\uff0c\u5347\u7ea7\u4e86 node \u7248\u672c\uff0c\u7ed3\u679c\u4ee5\u524d\u6b63\u5e38\u8dd1\u7684\u4e00\u4e2a\u7ec4\u4ef6\u91cc\u9762\u67d0\u4e2a\u5199\u6cd5\u53c8\u7528\u4e86\u65e7\u7248\u672c\u7684 node \uff0c\u53c8\u5f97\u53bb\u66f4\u65b0\u53e6\u5916\u4e00\u4e2a\u7ec4\u4ef6\u5e93\uff0c\u60f3\u8d77\u90a3\u4e2a\u8457\u540d\u7684\u201c\u9ed1\u6d1e\u201d\u4e86\u3002
\u6709\u4e00\u8bf4\u4e00\uff0c\u6709\u65f6\u662f\u8981\u641e\u4e2a\u7b80\u4fbf\u7684\u529f\u80fd\uff0c\u786e\u5b9e\u5f88\u4fbf\u6377\u3002", "date_published": "2025-08-21T06:33:16+00:00", "title": "\u73b0\u5728\u6d41\u884c\u7684 Node.js \u505a\u540e\u53f0\u6bd4\u4f20\u7edf\u7684 Java .Net \u6709\u54ea\u4e9b\u4f18\u52bf\uff1f", "id": "t/1153964" }, { "author": { "url": "member/fx", "name": "fx", "avatar": "https://cdn.v2ex.com/avatar/44c2/821d/32939_large.png?m=1758687863" }, "url": "t/1153505", "title": "\u73b0\u5728\u5927\u5bb6\u5f00\u53d1 api \u90fd\u7528\u4ec0\u4e48 node \u6846\u67b6?\u6709\u6ca1\u6709\u60f3 rails \u4e00\u6837\uff0c\u529f\u80fd\u9f50\u5168\u7684\u6846\u67b6\uff1f", "id": "t/1153505", "date_published": "2025-08-19T09:35:13+00:00", "content_html": "" }, { "author": { "url": "member/zhennann", "name": "zhennann", "avatar": "https://cdn.v2ex.com/avatar/97cf/ffd9/356142_large.png?m=1712331089" }, "url": "t/1150216", "title": "Prisma \u4e0d\u80fd\u4f18\u96c5\u7684\u652f\u6301 DTO\uff0c\u53ef\u4ee5\u8bd5\u8bd5 Vona ORM", "id": "t/1150216", "date_published": "2025-08-05T15:17:05+00:00", "content_html": "

\u5728 Nodejs \u751f\u6001\u4e2d\uff0cPrisma \u662f\u4e00\u4e2a\u975e\u5e38\u6d41\u884c\u7684 ORM \u5e93\uff0c\u652f\u6301 Typescript \uff0c\u63d0\u4f9b\u4e86\u975e\u5e38\u53cb\u597d\u7684\u7c7b\u578b\u63a8\u65ad\u80fd\u529b\u3002\u4f46\u662f\uff0cPrisma \u5374\u4e0d\u80fd\u4f18\u96c5\u7684\u652f\u6301 DTO \u3002\u5728\u4e0e\u5176\u4ed6\u540e\u7aef\u6846\u67b6\u6574\u5408\u65f6\uff0cDTO \u662f\u8fdb\u884c\u53c2\u6570\u9a8c\u8bc1\u3001\u751f\u6210 Swagger \u5143\u6570\u636e\u7684\u5173\u952e\u8282\u70b9\u3002\u5982\u679c\u4e0d\u80fd\u50cf\u63a8\u65ad\u7c7b\u578b\u4e00\u6837\u81ea\u52a8\u63a8\u65ad\u51fa DTO \uff0c\u90a3\u4e48\uff0c\u6211\u4eec\u5c31\u4ecd\u7136\u9700\u8981\u624b\u5de5\u521b\u5efa DTO \u3002\u968f\u7740\u4e1a\u52a1\u7684\u589e\u957f\uff0c\u590d\u6742\u7684\u8868\u95f4\u5173\u7cfb\u4f1a\u8ba9\u624b\u5de5\u8865\u5145 DTO \u7684\u5de5\u4f5c\u65e5\u76ca\u7e41\u91cd\u3002

\n

\u800c Vona ORM \u5c31\u63d0\u4f9b\u4e86\u975e\u5e38\u4fbf\u5229\u7684\u5de5\u5177\uff0c\u4f7f\u6211\u4eec\u53ef\u4ee5\u975e\u5e38\u76f4\u89c2\u7684\u52a8\u6001\u63a8\u65ad\u51fa DTO \uff0c\u5c31\u50cf\u63a8\u65ad\u7c7b\u578b\u4e00\u6837\uff0c\u4ece\u800c\u89e3\u653e\u6211\u4eec\u7684\u53cc\u624b\uff0c\u663e\u8457\u63d0\u5347\u751f\u4ea7\u529b\u3002\u751a\u81f3\u53ef\u4ee5\u8bf4\uff0c\u80fd\u591f\u81ea\u52a8\u63a8\u65ad DTO \uff0c\u4e3a Nodejs \u540e\u7aef\u6846\u67b6\u6253\u5f00\u4e86\u4e00\u6247\u7a97\u3002

\n

\u9650\u4e8e\u7bc7\u5e45\uff0c\u8fd9\u91cc\u4e0d\u5c55\u5f00\u8bb2\u89e3 Vona ORM \u6240\u6709\u7684\u77e5\u8bc6\u70b9\uff0c\u800c\u662f\u4ee5\u76ee\u5f55\u6811\u4e3a\u4f8b\uff0c\u6f14\u793a\u5982\u4f55\u67e5\u8be2\u4e00\u68f5\u76ee\u5f55\u6811\uff0c\u4ee5\u53ca\u5982\u4f55\u52a8\u6001\u751f\u6210 DTO \uff0c\u5e76\u6700\u7ec8\u751f\u6210 Swagger \u5143\u6570\u636e\u3002

\n

1. \u521b\u5efa Entity

\n

\u5728 VSCode \u4e2d\uff0c\u53ef\u4ee5\u901a\u8fc7\u53f3\u952e\u83dc\u5355Vona Create/Entity\u521b\u5efa Entity \u7684\u4ee3\u7801\u9aa8\u67b6\uff1a

\n
@Entity('demoStudentCategory')\nexport class EntityCategory extends EntityBase {\n @Api.field()\n name: string;\n\n @Api.field(v.optional())\n categoryIdParent?: TableIdentity;\n}\n
\n\n

2. \u521b\u5efa Model

\n

\u5728 VSCode \u4e2d\uff0c\u53ef\u4ee5\u901a\u8fc7\u53f3\u952e\u83dc\u5355Vona Create/Model\u521b\u5efa Model \u7684\u4ee3\u7801\u9aa8\u67b6\uff1a

\n
import { EntityCategory } from '../entity/category.ts';\n\n@Model({ entity: EntityCategory })\nexport class ModelCategory extends BeanModelBase<EntityCategory> {}\n
\n\n

3. \u521b\u5efa\u6811\u5f62\u7ed3\u6784

\n

\u5982\u679c\u8981\u521b\u5efa\u4e00\u68f5\u76ee\u5f55\u6811\uff0c\u672c\u8d28\u5c31\u662f\u5efa\u7acb Model \u5f15\u7528\u81ea\u8eab\u7684\u9012\u5f52\u7ed3\u6784\u3002Vona ORM \u540c\u6837\u652f\u6301 4 \u79cd\u5173\u7cfb\uff1a1 \u5bf9 1\u30011 \u5bf9\u591a\u3001\u591a\u5bf9 1\uff0c\u591a\u5bf9\u591a\u3002\u90a3\u4e48\uff0c\u5728\u8fd9\u91cc\uff0c\u6211\u4eec\u5c31\u9700\u8981\u91c7\u75281 \u5bf9\u591a\u6765\u521b\u5efa\u76ee\u5f55\u7684\u81ea\u8eab\u5f15\u7528\u5173\u7cfb\u3002

\n
import { EntityCategory } from '../entity/category.ts';\n\n@Model({\n entity: EntityCategory,\n+ relations: {\n+ children: $relation.hasMany(() => ModelCategory, 'categoryIdParent', {\n+ autoload: true,\n+ columns: ['id', 'name'],\n+ }),\n+ },\n})\nexport class ModelCategory extends BeanModelBase<EntityCategory> {}\n
\n\n

4. \u521b\u5efa Controller

\n

\u5728 VSCode \u4e2d\uff0c\u53ef\u4ee5\u901a\u8fc7\u53f3\u952e\u83dc\u5355Vona Create/Controller\u521b\u5efa Controller \u7684\u4ee3\u7801\u9aa8\u67b6\uff1a

\n
@Controller()\nexport class ControllerCategory extends BeanBase {}\n
\n

\u63a5\u4e0b\u6765\u6211\u4eec\u521b\u5efa\u4e00\u4e2a Api \uff0c\u7528\u4e8e\u83b7\u53d6\u76ee\u5f55\u6811\uff1a

\n
export class ControllerCategory extends BeanBase {\n @Web.get('getCategoryTree')\n async getCategoryTree() {\n }\n}\n
\n\n

5. \u67e5\u8be2\u76ee\u5f55\u6811

\n

\u4e00\u822c\u800c\u8a00\uff0c\u6211\u4eec\u8fd8\u9700\u8981\u521b\u5efa\u4e00\u4e2a Service \uff0c\u4ece\u800c\u5b9e\u73b0\u4ee5\u4e0b\u8c03\u7528\u94fe\uff1aController->Service->Model->\u64cd\u4f5c\u6570\u636e\u5e93\u3002\u4e3a\u4e86\u7b80\u5316\u8d77\u89c1\uff0c\u5728\u8fd9\u91cc\uff0c\u6211\u4eec\u76f4\u63a5\u5728 Controller \u4e2d\u8c03\u7528 Model \u65b9\u6cd5\uff1a

\n
export class ControllerCategory extends BeanBase {\n @Web.get('getCategoryTree')\n async getCategoryTree() {\n const tree = await this.scope.model.category.select({\n columns: ['id', 'name'],\n });\n return tree;\n }\n}\n
\n\n

\u7531\u4e8e\u524d\u9762\u6211\u4eec\u8bbe\u7f6e children \u5173\u7cfb\u4e3aautoload: true\uff0c\u56e0\u6b64\uff0c\u67e5\u8be2\u7ed3\u679ctree\u5c31\u662f\u4e00\u68f5\u5b8c\u6574\u7684\u76ee\u5f55\u6811\u3002\u4e0b\u9762\u6211\u4eec\u770b\u4e00\u4e0btree\u7684\u7c7b\u578b\u63a8\u65ad\u6548\u679c\uff1a

\n

\"1.png\"

\n

\"2.png\"

\n

6. \u81ea\u52a8\u63a8\u65ad DTO

\n

\u73b0\u5728\u6211\u4eec\u81ea\u52a8\u63a8\u65ad DTO \uff0c\u5e76\u4e14\u8bbe\u4e3a API \u7684\u8fd4\u56de\u6570\u636e\u7684\u7c7b\u578b\uff1a

\n
export class ControllerCategory extends BeanBase {\n @Web.get('getCategoryTree')\n+ @Api.body(v.array(v.object($Dto.get(() => ModelCategory, { columns: ['id', 'name'] }))))\n async getCategoryTree() {\n const tree = await this.scope.model.category.select({\n columns: ['id', 'name'],\n });\n return tree;\n }\n}\n
\n\n

\u540c\u6837\uff0c\u7531\u4e8e\u524d\u9762\u6211\u4eec\u8bbe\u7f6e children \u5173\u7cfb\u4e3aautoload: true\uff0c\u56e0\u6b64\uff0c$Dto.get\u751f\u6210\u7684 DTO \u5c31\u662f\u4e00\u68f5\u5b8c\u6574\u7684\u76ee\u5f55\u6811\u3002\u4e0b\u9762\u6211\u4eec\u770b\u4e00\u4e0b API \u7684 Swagger \u6548\u679c\uff1a

\n

\"3.png\"

\n

\"4.png\"

\n

\"5.png\"

\n

\u4ece\u793a\u610f\u56fe\u4e2d\uff0c\u6211\u4eec\u53ef\u4ee5\u6e05\u6670\u7684\u770b\u5230\uff0c\u8fd9\u68f5\u6811\u5f15\u7528\u7684 children \u7c7b\u578b\u662f\u540d\u79f0\u4e3ademo-student.entity.category_2c7d642ee581efa300341e343180fbb0ecdc785d\u7684\u52a8\u6001 Entity \u7684\u6570\u7ec4\uff0c\u4ece\u800c\u5f62\u6210\u4e00\u79cd\u9012\u5f52\u7684\u5f15\u7528\u5173\u7cfb\u3002

\n

7. \u5c01\u88c5 DTO

\n

\u867d\u7136\u6211\u4eec\u5df2\u7ecf\u5b9e\u73b0\u4e86\u9884\u671f\u7684\u76ee\u6807\uff0c\u4f46\u662f Vona ORM \u63d0\u4f9b\u7684\u80fd\u529b\u8fd8\u6ca1\u6709\u7ed3\u675f\u3002\u6211\u4eec\u53ef\u4ee5\u521b\u5efa\u4e00\u4e2a\u65b0\u7684 DTO \uff0c\u5c06\u524d\u9762\u7684\u4ee3\u7801$Dto.get(() => ModelCategory, { columns: ['id', 'name'] })\u5c01\u88c5\u8d77\u6765\uff0c\u4ece\u800c\u7528\u4e8e\u5176\u4ed6\u5730\u65b9\uff1a

\n

\u5728 VSCode \u4e2d\uff0c\u53ef\u4ee5\u901a\u8fc7\u53f3\u952e\u83dc\u5355Vona Create/Dto\u521b\u5efa DTO \u7684\u4ee3\u7801\u9aa8\u67b6\uff1a

\n
@Dto()\nexport class DtoCategoryTree {}\n
\n

\u7136\u540e\u6211\u4eec\u901a\u8fc7\u7ee7\u627f\u673a\u5236\u6765\u5c01\u88c5 DTO\uff1a

\n
@Dto()\nexport class DtoCategoryTree \n+ extends $Dto.get(() => ModelCategory, { columns: ['id', 'name'] }) {}\n
\n

\u73b0\u5728\uff0c\u6211\u4eec\u518d\u4f7f\u7528\u65b0\u521b\u5efa\u7684 DTO \u6765\u6539\u9020\u524d\u9762\u7684 API \u4ee3\u7801\uff1a

\n
export class ControllerCategory extends BeanBase {\n @Web.get('getCategoryTree')\n+ @Api.body(v.array(v.object(DtoCategoryTree)))\n+ async getCategoryTree(): Promise<DtoCategoryTree[]>{\n const tree = await this.scope.model.category.select({\n columns: ['id', 'name'],\n });\n return tree;\n }\n}\n
\n\n" }, { "author": { "url": "member/llej", "name": "llej", "avatar": "https://cdn.v2ex.com/avatar/b4e7/fabc/451595_large.png?m=1596437487" }, "url": "t/1147752", "title": "\u6bd4 prisma studio \u66f4\u597d\u6027\u80fd\u7684\u7c7b studio \u6570\u636e\u7ba1\u7406", "id": "t/1147752", "date_published": "2025-07-25T11:15:24+00:00", "content_html": "

\u901a\u8fc7 https://github.com/2234839/TsFullStack/commit/7111be9b1a75259bab622f670f3f3e8ff39d830f \u7684\u52aa\u529b\uff0c\u73b0\u5728 TsFullStack \u7684 AutoTable \u4e0d\u4f1a\u67e5\u8be2\u51fa\u5168\u90e8\u7684\u5173\u8054\u5bf9\u8c61\u4e86

\n

\u8fd9\u662f\u4f18\u5316\u524d\u7684\uff0cfindMany \u8db3\u8db3\u6709 308kB \u56e0\u4e3a\u7528\u6237\u6240\u5173\u8054\u7684\u5176\u4ed6\u6570\u636e\u7684 id \u548c\u547d\u540d\u5b57\u6bb5\u4e5f\u67e5\u51fa\u6765\u4e86\u3002

\n

\"\"

\n

\u4f18\u5316\u540e\u9aa4\u964d\u5230 3.4kB

\n

\"\"

\n

\u800c prisma studio \u9700\u8981 21.7kB

\n

\"\"

\n

\u8fd9\u662f\u56e0\u4e3a prisma studio \u867d\u7136\u4e5f\u4f1a\u67e5\u8be2\u6240\u6709\u5173\u8054\u6570\u636e\uff0c\u4f46\u4ed6\u53ea\u67e5\u8be2\u4e86 id \uff0c\u800c\u6211\u4e4b\u524d\u4e3a\u4e86\u53cb\u597d\u7684\u663e\u793a\u6570\u636e\u6240\u4ee5\u67e5\u8be2\u4e86\u4e00\u4e2a\u7528\u4e8e\u663e\u793a\u7684\u5b57\u6bb5\uff0c\u6240\u4ee5\u4f1a\u6bd4\u4ed6\u5927\u8bb8\u591a

\n

\u800c\u73b0\u5728\u6211\u53cd\u800c\u6bd4 prisma studio \u66f4\u5c0f\uff0c\u8fd9\u662f\u56e0\u4e3a\u6211\u4e0d\u518d\u67e5\u8be2 id \u4e86\uff0c\u800c\u662f\u901a\u8fc7 _count \u6765\u67e5\u8be2\u5173\u8054\u6570\u91cf\u3002\u6240\u4ee5\u80fd\u591f\u6bd4 prisma studio \u66f4\u5c0f\u3002

\n

\u800c\u4e3a\u4e86\u5b9e\u73b0\u5173\u8054\u5b57\u6bb5\u7684\u7f16\u8f91\u6211\u4e5f\u5927\u5200\u9614\u65a7\u7684\u91cd\u6784\u4e86\u6211\u7684\u4ee3\u7801\uff0c\u80fd\u591f\u505a\u5230\u5728\u4e0d\u52a0\u8f7d\u5168\u91cf\u5173\u8054\u5173\u7cfb\u7684\u60c5\u51b5\u4e0b\u52a8\u6001\u901a\u8fc7\u5206\u9875\u6570\u636e\u611f\u77e5\u5230\u88ab\u5173\u8054\u8868\u548c\u5f53\u524d\u6570\u636e\u884c\u7684\u5173\u8054\u5173\u7cfb\u3002

\n" }, { "author": { "url": "member/Chuckle", "name": "Chuckle", "avatar": "https://cdn.v2ex.com/avatar/0b33/4c86/604103_large.png?m=1752071689" }, "url": "t/1146146", "title": "node \u600e\u4e48\u83b7\u53d6\u526a\u5207\u677f\u4e2d\u590d\u5236\u7684\u6587\u4ef6\u4fe1\u606f", "id": "t/1146146", "date_published": "2025-07-18T07:33:11+00:00", "content_html": "\u5728\u5199 vscode \u63d2\u4ef6\uff0cvscode.env.clipboard.readText()\u3001clipboard.readSync()\u3001pbpaste \u8fd9\u4e9b\u5185\u7f6e\u3001\u4e09\u65b9\u3001\u547d\u4ee4\u90fd\u53ea\u80fd\u83b7\u53d6\u5230\u6587\u4ef6\u540d\uff0c\u526a\u5207\u677f\u5185\u590d\u5236\u7684\u6587\u4ef6\u5e94\u8be5\u6709\u7279\u6b8a\u7684\u683c\u5f0f\u5427\uff0c\u600e\u4e48\u4ece\u91cc\u9762\u83b7\u53d6\u5230\u6587\u4ef6\u8def\u5f84\u3002" }, { "author": { "url": "member/Gitborlando", "name": "Gitborlando", "avatar": "https://cdn.v2ex.com/gravatar/9a67e99da8776a97d542b37516fdbca0?s=73&d=retro" }, "url": "t/1144960", "title": "\u5199\u4e86\u4e2a js \u5c0f\u5de5\u5177\u5e93, \u5e0c\u671b\u5927\u5bb6\u7ed9\u70b9\u5efa\u8bae", "id": "t/1144960", "date_published": "2025-07-13T15:07:28+00:00", "content_html": "

github: https://github.com/gitborlando/utils

\n" }, { "author": { "url": "member/NobodyVe2x", "name": "NobodyVe2x", "avatar": "https://cdn.v2ex.com/avatar/523d/2a03/232700_large.png?m=1729694002" }, "url": "t/1140269", "title": "NodeJS \u963f\u91cc\u4e91\u670d\u52a1\u5668\uff0c\u7ecf\u5e38\u9047\u5230\u6574\u4e2a\u670d\u52a1\u5668\u5361\u6b7b\uff0c\u7cfb\u7edf\u76d8\u8bfb\u64cd\u4f5c\u88ab\u5360\u6ee1", "id": "t/1140269", "date_published": "2025-06-22T10:15:08+00:00", "content_html": "

\u7ecf\u5e38\u9047\u5230\u6574\u4e2a\u670d\u52a1\u5668\u5361\u6b7b\uff0c\u7cfb\u7edf\u76d8\u8bfb\u64cd\u4f5c\u88ab\u5360\u6ee1\uff0c\u5185\u5b58\u786e\u662f\u6b63\u5e38

\n

\u8865\u5145\u4e00\u4e0b\uff0c\u8fd9\u4e2a\u9879\u76ee\u4f7f\u7528 bytenode \u7f16\u8bd1\u540e\u6587\u4ef6\u5728\u8dd1\uff0c\u4e0d\u662f\u6e90\u4ee3\u7801\u8dd1\u3002

\n

axios \u4e5f\u505a\u4e86\u7edf\u4e00\u5904\u7406

\n

const axios = require('axios');\nconst https = require('https');

\n

// \u5168\u5c40 10 \u79d2\u8d85\u65f6\naxios.defaults.timeout = 10000;

\n

// \u521b\u5efa\u81ea\u5b9a\u4e49\u7684 HTTPS \u4ee3\u7406\uff0c\u9650\u5236\u8fde\u63a5\u6570\nconst httpsAgent = new https.Agent({\nkeepAlive: true,\nkeepAliveMsecs: 30000,\nmaxSockets: 30, // \u9650\u5236\u5e76\u53d1\u8fde\u63a5\u6570\nmaxFreeSockets: 5, // \u9650\u5236\u7a7a\u95f2\u8fde\u63a5\u6570\ntimeout: 10000, // \u8fde\u63a5\u8d85\u65f6\n});

\n

// \u521b\u5efa axios \u5b9e\u4f8b\nconst apiClient = axios.create({\nhttpsAgent: httpsAgent,\ntimeout: 10000, // \u8bf7\u6c42\u8d85\u65f6\nmaxRedirects: 3,\n});

\n

module.exports = apiClient

\n

\u6709\u6ca1\u6709\u5927\u4f6c\u80fd\u51fa\u51fa\u4e3b\u610f\uff0c\u5230\u5e95\u662f\u54ea\u91cc\u51fa\u95ee\u9898\u4e86\uff1f

\n" }, { "author": { "url": "member/riceball", "name": "riceball", "avatar": "https://cdn.v2ex.com/gravatar/f7b81e783188e376c9f046ae1285d47f?s=73&d=retro" }, "url": "t/1137432", "title": "\u4e0d\u7528\u7ee7\u627f\u5c31\u80fd\u7ed9\u7c7b\u52a0\u4e8b\u4ef6\u7cfb\u7edf\uff1f\u8fd9\u6ce2\u539f\u578b\u94fe\u64cd\u4f5c\u6211\u7ed9\u6ee1\u5206", "id": "t/1137432", "date_published": "2025-06-09T09:43:27+00:00", "content_html": "

long long ago,\u6709\u8fd9\u4e48\u4e00\u4e2a\u4e8b\u4ef6\u5e93

\n

\u8bba\u5982\u4f55\u4f18\u96c5\u5730\u7ed9\u7956\u4f20\u4ee3\u7801\u62cd\u4e2a eventable() \u5c31\u80fd\u7528

\n

\ud83d\udca5 \u4f20\u7edf\u7ee7\u627f\u306e\u75db\uff0c\u8c01\u61c2\u554a\uff1f

\n

\u5f53\u4f60\u60f3\u7ed9\u4e00\u4e2a \u5df2\u7ecf\u6709 3 \u5c42\u7ee7\u627f\u7684\u7956\u4f20 Class \u52a0\u4e8b\u4ef6\u7cfb\u7edf\uff1a

\n
class \u7956\u4f20 Class extends \u7237\u7237 Class { /* ... */ } \n\n// \u4f20\u7edf\u65b9\u6848\uff1a\u786c\u7740\u5934\u76ae\u518d\u7ee7\u627f\u4e00\u5c42 \nclass \u6211\u7684 Class extends \u7956\u4f20 Class, EventEmitter { /* \u591a\u91cd\u7ee7\u627f\uff1f\u4e0d\u5b58\u5728\u7684\uff01\u76f4\u63a5\u62a5\u9519\uff01 */ } \n
\n

\u75db\u70b9\u66b4\u51fb\uff1a

\n\n

\u2728 \u4e8b\u4ef6\u7cfb\u7edf\u7684\u795e\u4e4b\u53f3\u624b\uff1aeventable()

\n

\u73b0\u5728\u53ea\u9700\u4e00\u884c\u9b54\u6cd5\uff1a

\n
import { eventable } from 'events-ex'; \n\nclass \u7956\u4f20 Java \u98ce Class extends \u7237\u7237 Class { /* ... */ } // \u4fdd\u6301\u539f\u6837\n\n// \u6ce8\u5165\u4e8b\u4ef6\u80fd\u529b\uff0c\u4f46\u53ea\u6ce8\u5165\uff08\u66b4\u9732\uff09 on/emit \u65b9\u6cd5\uff08\u6df1\u85cf\u529f\u4e0e\u540d\uff09 \neventable(\u7956\u4f20 Java \u98ce Class, { \n include: ['on', 'emit'] // \u50cf\u505a\u5916\u79d1\u624b\u672f\u4e00\u6837\u7cbe\u51c6 \n}); \n\n// \u7528\u6cd5\u548c EventEmitter \u4e00\u6bdb\u4e00\u6837 \nconst obj = new \u7956\u4f20 Java \u98ce Class(); \nobj.on('data', handleData); \nobj.emit('data', payload); \n
\n

\u6838\u5fc3\u7406\u5ff5\uff1a

\n\n

\ud83e\udd2f \u9ad8\u7ea7\u73a9\u6cd5\uff1a\u7ed9\u65b9\u6cd5\u52a0\u4e8b\u4ef6\u94a9\u5b50

\n

\u66f4\u9a9a\u7684\u662f\u8fde\u65b9\u6cd5\u90fd\u80fd\u6302\u4e8b\u4ef6\uff1a

\n
class \u6570\u636e\u5e93 { \n connect() { \n // \u539f\u59cb\u65b9\u6cd5\u4fdd\u6301\u7eaf\u6d01 \n console.log('\u5efa\u7acb\u8fde\u63a5'); \n } \n} \n\n// \u7ed9 connect \u65b9\u6cd5\u52a0\u524d\u7f6e\u4e8b\u4ef6 \neventable(\u6570\u636e\u5e93, { \n methods: { \n connect() { \n this.emit('pre-connect'); // \u89e6\u53d1\u4e8b\u4ef6 \n this.super(); // \u8c03\u7528\u539f\u65b9\u6cd5\uff08 this.super \u662f\u9b54\u6cd5\u5173\u952e\u5b57\uff01\uff09\n } \n } \n}); \n\n// \u76d1\u542c\u6570\u636e\u5e93\u8fde\u63a5\u4e8b\u4ef6 \nconst db = new \u6570\u636e\u5e93(); \ndb.on('pre-connect', () => { \n console.log('\u6211\u8981\u5f00\u59cb\u8fde\u63a5\u4e86\uff0c\u5404\u7ec4\u4ef6\u6ce8\u610f\uff01'); \n}); \ndb.connect()\n
\n

\u8f93\u51fa\u7ed3\u679c\uff1a

\n
\u6211\u8981\u5f00\u59cb\u8fde\u63a5\u4e86\uff0c\u5404\u7ec4\u4ef6\u6ce8\u610f\uff01 \n\u5efa\u7acb\u8fde\u63a5 \n
\n

\ud83d\udee0 \u9632\u7ffb\u8f66\u6307\u5357

\n\n

\u7075\u9b42\u53d1\u95ee\uff1a

\n

\u4f60\u4eec\u9879\u76ee\u91cc\u6709\u90a3\u79cd \u4e0d\u6562\u52a8\u53c8\u5fc5\u987b\u589e\u5f3a \u7684\u7c7b\u5417\uff1f\u5feb\u6765\u8bd5\u8bd5\u8fd9\u5957\u65e0\u75db\u4e8b\u4ef6\u6ce8\u5165\u65b9\u6848\uff01

\n

\u4f20\u9001\u95e8\uff1a

\n

\ud83d\udc49 GitHub \u5730\u5740 | \ud83d\udcda \u5b8c\u6574 API \u6587\u6863

\n

\u6295\u5582\u59ff\u52bf\uff1a

\n
npm install events-ex\n
\n

\u8ba8\u8bba\u70b9\uff1a

\n\n" }, { "author": { "url": "member/xiaolingxinna", "name": "xiaolingxinna", "avatar": "https://cdn.v2ex.com/avatar/89cd/7585/191542_large.png?m=1554195946" }, "url": "t/1136381", "title": "\u505a\u4e86\u4e00\u4e2a\u51fd\u6570\u5f0f\u3001\u5e26\u7c7b\u578b\u3001\u8d85\u987a\u624b\u7684\u5fae\u578b\u4e8b\u4ef6\u5e93\uff0c\u5df2\u53d1\u5e03\u5230 npm", "id": "t/1136381", "date_published": "2025-06-04T12:44:03+00:00", "content_html": "

github: https://github.com/Misaka-0x447f/createTypedEvent
\nnpm: https://www.npmjs.com/package/@misaka17535/create-typed-event

\n

\u76f8\u6bd4\u5176\u4ed6\u4e8b\u4ef6\u5e93\uff0c\u9996\u5148\u662f\u5e26\u7c7b\u578b\uff0c\u8ba9\u7528\u6237\u80fd\u77e5\u9053 payload \u7684\u7c7b\u578b\uff1b\u5176\u6b21\u662f\u51fd\u6570\u5f0f\uff0c\u4e0d\u518d\u9700\u8981\u624b\u6572\u4e8b\u4ef6\u540d\u3002\u7136\u540e\u662f sub \u51fd\u6570\u81ea\u52a8\u8fd4\u56de unsub \u51fd\u6570\uff0c\u4e0d\u518d\u5fc5\u987b\u4f20\u5165 sub \u65f6\u7684 listener\uff1a

\n
const misakaStateChange = createTypedEvent<{ selfDestructionInProgress: boolean }>()\n// returns unsub function without defining handler outside\nconst unsub = misakaStateChange.sub((payload) => console.log(payload))\nmisakaStateChange.dispatch({selfDestructionInProgress: true})\nunsub()\n
\n

>>> { selfDestructionInProgress: true }

\n

\u53e6\u5916\u8fd8\u81ea\u5e26 react hook \uff0c\u5b8c\u7f8e\u6865\u63a5 react \u54cd\u5e94\u5f0f\u53d8\u91cf\uff0c\u5982\u679c\u4f60\u60f3\u4f60\u4e5f\u53ef\u4ee5\u8f7b\u677e\u5199\u51fa\u5176\u4ed6\u54cd\u5e94\u5f0f\u6846\u67b6\u7684\u7248\u672c\u3002

\n

\u662f\u65b0\u5305\uff0c\u4f46\u662f\u5df2\u7ecf\u5728\u5404\u79cd\u5185\u90e8\u9879\u76ee\u91cc\u7528\u4e86\u4e24\u4e09\u5e74\u4e86\uff0c\u7528\u8fc7\u7684\u540c\u4e8b\u90fd\u8bf4\u597d\u3002

\n" }, { "author": { "url": "member/ckken", "name": "ckken", "avatar": "https://cdn.v2ex.com/avatar/5ce1/6961/47722_large.png?m=1748939543" }, "url": "t/1134933", "date_modified": "2025-05-29T05:17:09+00:00", "content_html": "
\n

\u4ece\u591a\u4e2a\u4f9d\u8d56\u5305\u5230 1 \u4e2a\u8fd0\u884c\u65f6\uff0c\u4ece\u590d\u6742\u914d\u7f6e\u5230\u96f6\u914d\u7f6e\u5f00\u53d1\u2014\u2014\u8fd9\u5c31\u662f Bun \u5e26\u7ed9 MCP Server \u5f00\u53d1\u7684\u9769\u547d\u6027\u53d8\u5316

\n
\n

\u4f20\u7edf Node.js \u5f00\u53d1\u7684\u75db\u70b9

\n

\u5728\u4f20\u7edf\u7684 MCP Server \u5f00\u53d1\u4e2d\uff0c\u6211\u4eec\u9700\u8981\u642d\u5efa\u4e00\u5957\u590d\u6742\u7684\u5de5\u5177\u94fe\uff1a

\n

\ud83d\udce6 \u4f9d\u8d56\u5730\u72f1

\n

\u4ee5 Figma-Context-MCP \u4e3a\u4f8b\uff0c\u4e00\u4e2a\u6807\u51c6\u7684 TypeScript MCP \u9879\u76ee\u9700\u8981\uff1a

\n

\u6784\u5efa\u5de5\u5177\u94fe

\n\n

\u5f00\u53d1\u670d\u52a1

\n\n

\u6d4b\u8bd5\u6846\u67b6

\n\n

\ud83d\udc0c \u5f00\u53d1\u4f53\u9a8c\u75db\u70b9

\n\n

Bun\uff1a\u4e00\u4e2a\u8fd0\u884c\u65f6\u89e3\u51b3\u6240\u6709\u95ee\u9898

\n

f2c-mcp \u9879\u76ee \u5c55\u793a\u4e86 Bun \u7684\u5b8c\u7f8e\u89e3\u51b3\u65b9\u6848\uff1a

\n

\"Bun-vs-node-comparison-1-1024x704.png\"

\n

\ud83d\ude80 \u7edf\u4e00\u6784\u5efa\uff1a\u96f6\u914d\u7f6e\u5f00\u7bb1\u5373\u7528

\n
{\n \"build\": \"bun run bun.build.script.ts\",\n \"dev\": \"bun --watch run bun.build.script.ts\"\n}\n
\n

\u4e00\u4e2a\u811a\u672c\u641e\u5b9a\u6240\u6709\u6784\u5efa\u9700\u6c42\uff1a

\n
const script = process.env.npm_lifecycle_script || ''\nconst isDev = script.includes('--watch')\n\nconst result = await Bun.build({\n entrypoints: ['src/stdio.ts', 'src/cli.ts', 'src/streamable-http.ts'],\n outdir: 'dist',\n format: 'cjs',\n target: 'node',\n sourcemap: 'linked',\n minify: !isDev,\n env: isDev ? 'inline' : 'disable',\n})\n
\n

\u5173\u952e\u4f18\u52bf\uff1a

\n\n

\ud83e\uddea \u539f\u751f\u6d4b\u8bd5\uff1a\u544a\u522b\u914d\u7f6e\u5730\u72f1

\n
{\n \"test\": \"bun test src/test/api.test.ts\",\n \"e2e\": \"bun test src/test/e2e.test.ts\"\n}\n
\n

\u65e0\u9700\u914d\u7f6e\uff1a

\n\n

\ud83c\udf10 \u5b8c\u7f8e\u670d\u52a1\uff1a\u751f\u4ea7\u7ea7 Web \u652f\u6301

\n
{\n \"http:dev\": \"bun --env-file=.env --watch run src/streamable-http.ts\",\n \"http:prod\": \"bun --env-file= run src/streamable-http.ts\"\n}\n
\n

Bun 1.2+\u7684\u7a81\u7834\uff1a

\n\n

\u6027\u80fd\u5bf9\u6bd4\uff1a\u6570\u636e\u8bf4\u8bdd

\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n
\u6307\u6807Node.js \u5de5\u5177\u94feBun \u65b9\u6848\u63d0\u5347\u5e45\u5ea6
\u9879\u76ee\u542f\u52a8\u65f6\u95f43-5 \u79d20.5-1 \u79d25 \u500d\u63d0\u5347
\u70ed\u91cd\u8f7d\u901f\u5ea62-3 \u79d2<500ms6 \u500d\u63d0\u5347
\u6d4b\u8bd5\u6267\u884c\u901f\u5ea610-15 \u79d22-3 \u79d25 \u500d\u63d0\u5347
\u5185\u5b58\u5360\u7528200-300MB50-80MB3 \u500d\u51cf\u5c11
\u4f9d\u8d56\u5305\u6570\u91cf15+1\u6781\u7b80\u5316

\u8fc1\u79fb\u6307\u5357\uff1a3 \u6b65\u5b8c\u6210\u5347\u7ea7

\n

Step 1: \u66ff\u6362 package.json \u811a\u672c

\n
{\n \"scripts\": {\n \"build\": \"bun run build.script.ts\",\n \"dev\": \"bun --watch run build.script.ts\",\n \"test\": \"bun test\",\n \"serve\": \"bun --watch run src/server.ts\"\n }\n}\n
\n

Step 2: \u521b\u5efa\u6784\u5efa\u811a\u672c

\n
// build.script.ts\nconst result = await Bun.build({\n entrypoints: ['src/index.ts'],\n outdir: 'dist',\n target: 'node'\n})\n
\n

Step 3: \u79fb\u9664\u5197\u4f59\u4f9d\u8d56

\n
# \u53ef\u4ee5\u79fb\u9664\u7684\u5305\nnpm uninstall tsup typescript ts-jest jest node-watch cross-env\n
\n

\u8de8\u5e73\u53f0\u90e8\u7f72\uff1a\u4e00\u6b21\u6784\u5efa\uff0c\u5904\u5904\u8fd0\u884c

\n

Bun \u7684\u4ea4\u53c9\u7f16\u8bd1\u80fd\u529b\u8ba9\u90e8\u7f72\u53d8\u5f97\u6781\u5176\u7b80\u5355\uff1a

\n
# \u7f16\u8bd1\u4e3a\u5404\u5e73\u53f0\u53ef\u6267\u884c\u6587\u4ef6\nbun build --compile --target=linux-x64 ./src/index.ts\nbun build --compile --target=windows-x64 ./src/index.ts\nbun build --compile --target=darwin-x64 ./src/index.ts\n
\n

\u603b\u7ed3\uff1a\u5f00\u53d1\u4f53\u9a8c\u7684\u8d28\u53d8

\n

\u4ece Node.js \u5230 Bun \u7684\u8fc1\u79fb\u4e0d\u4ec5\u4ec5\u662f\u5de5\u5177\u7684\u66ff\u6362\uff0c\u800c\u662f\u5f00\u53d1\u54f2\u5b66\u7684\u5347\u7ea7\uff1a

\n\n

\u5728 MCP Server \u5f00\u53d1\u7684\u65b0\u65f6\u4ee3\uff0cBun \u4e0d\u4ec5\u4ec5\u662f\u4e00\u4e2a\u66f4\u5feb\u7684 Node.js \u66ff\u4ee3\u54c1\uff0c\u5b83\u91cd\u65b0\u5b9a\u4e49\u4e86\u5168\u6808 Javascript \u5f00\u53d1\u7684\u53ef\u80fd\u6027\u3002

\n

\u7acb\u5373\u5f00\u59cb\u4f60\u7684 Bun + MCP \u4e4b\u65c5\uff0c\u4f53\u9a8c 3 \u500d\u6548\u7387\u63d0\u5347\u7684\u5f00\u53d1\u5feb\u611f\uff01

\n", "date_published": "2025-05-28T08:26:13+00:00", "title": "\u544a\u522b Node.js \u5de5\u5177\u94fe\u5730\u72f1\uff1a Bun \u5982\u4f55\u8ba9 MCP Server \u5f00\u53d1\u6548\u7387\u7ffb 3 \u500d", "id": "t/1134933" }, { "author": { "url": "member/qingyingwan", "name": "qingyingwan", "avatar": "https://cdn.v2ex.com/gravatar/9202cf2201e9403d0f02a5d94d4dfe52?s=73&d=retro" }, "url": "t/1133390", "title": "redis \u96c6\u7fa4\u6a21\u5f0f\u652f\u6301\u6279\u91cf\u64cd\u4f5c\u5e93 mget/mset", "id": "t/1133390", "date_published": "2025-05-21T16:43:46+00:00", "content_html": "

\u4e4b\u524d\u5728\u9879\u76ee\u91cc\u9762\u7528\u7684\uff0c\u5f00\u6e90\u5206\u4eab\u4e0b\n\u5355\u6b21\u64cd\u4f5c\u5927\u91cf key \u7684\u573a\u666f\u53ef\u4ee5\u63d0\u5347\u5de8\u591a\u6027\u80fd\uff0c\u6211\u662f\u5728\u63a8\u8350\u7cfb\u7edf\u91cc\u9762\u7528\u7684\uff0c\u5b9e\u8df5\u4e2d\u7ebf\u4e0a\u9879\u76ee redisP90 \u5ef6\u8fdf\u53ef\u4ee5\u4ece 200+ms \u964d\u4f4e\u5230 10+ms\nhttps://www.npmjs.com/package/redis-cluster-batch?activeTab=readme

\n" }, { "author": { "url": "member/flyingcrp", "name": "flyingcrp", "avatar": "https://cdn.v2ex.com/avatar/74bc/9a93/612598_large.png?m=1747295037" }, "url": "t/1131986", "title": "\ud83d\ude02\ud83d\ude02\u6d6a\u8d39\u4e86 3 \u5929\u65f6\u95f4\u5c1d\u8bd5\u5728\u65b0\u9879\u76ee\u4e2d\u4f7f\u7528 prisma\uff0c\u6700\u540e\u8fd8\u662f\u51b3\u5b9a\u56de\u5230 typeorm", "id": "t/1131986", "date_published": "2025-05-15T07:46:27+00:00", "content_html": "

\u5144\u5f1f\u4eec\uff0cprisma \u6709\u5751\uff0c\u5feb\u8dd1\ud83c\udfc3\u200d\u2640\ufe0f\ud83d\udca8\ud83d\udca8\ud83d\udca8\ud83d\udca8\ud83d\udca8\ud83d\udca8\ud83d\udca8\ud83d\udca8

\n\n

https://github.com/prisma/prisma/issues/101421

\n

https://github.com/prisma/prisma/issues/10142#issuecomment-1835279273

\n

https://github.com/prisma/prisma/issues/20128

\n\n

\u5728\u9047\u5230\u4e0a\u9762 1,2 \u7684\u65f6\u5019\u786c\u7740\u5934\u76ae\u7ee7\u7eed\uff0c\u4f46\u662f\u9047\u5230 3 \u7684\u65f6\u5019\u5f7b\u5e95\u8ba9\u6211\u653e\u5f03\u4e86\u5b83\u3002

\n

\u63d0\u6876\u8dd1\u8def\u4e86 \ud83c\udfc3\u200d\u2640\ufe0f\ud83d\udca8\ud83d\udca8\ud83d\udca8\ud83d\udca8\ud83d\udca8\ud83d\udca8\ud83d\udca8

\n

\u5144\u5f1f\u4eec\uff0c\u8282\u7ea6\u65f6\u95f4\uff0c\u539f\u7406 prisma

\n" }, { "author": { "url": "member/cj323", "name": "cj323", "avatar": "https://cdn.v2ex.com/gravatar/55d8713a4741083ba73747a518298a1f?s=73&d=retro" }, "url": "t/1131622", "date_modified": "2025-05-14T02:19:06+00:00", "content_html": "

bun v1 \u6709\u4e00\u6bb5\u65f6\u95f4\u4e86\uff0c\u4ee5\u4e3a\u53ef\u4ee5\u7528\u4e86\u3002\u5728\u4e00\u4e2a\u5c0f\u7684\u9879\u76ee\u91cc\u8bd5\u4e86\u4e00\u4e0b\uff0c\u7ed3\u679c\u53d1\u73b0\u54ea\u6015\u5c0f\u9879\u76ee\u8fd8\u662f\u57fa\u672c\u7528\u4e0d\u4e86\u3002

\n
    \n
  1. \u7a33\u5b9a\u6027\u5dee\uff0c\u7ecf\u5e38\u83ab\u540d segfault/memory leak \u3002\u8d34\u5230 github \u53d1\u73b0\u5f80\u5f80\u90fd\u662f\u65b0\u7248\u672c\u8fed\u4ee3\u65f6\u6ca1\u6d4b\u8bd5\u597d\uff0c\u4fa7\u9762\u8bf4\u660e\u5176\u7a33\u5b9a\u6027\u582a\u5fe7\u3002
  2. \n
  3. \u517c\u5bb9\u6027\u5dee\uff0c\u4e00\u5230 linux \u73af\u5883\u5c31\u5404\u79cd\u51fa\u95ee\u9898\u3002\u6211\u7528\u670d\u52a1\u5668\u7528\u7684 ubuntu 24 \uff0c\u7ecf\u5e38\u5d29\u6e83\u6216\u8005\u62a5\u9519\u3002docker \u7528\u5b98\u65b9\u7684 image \u4e5f\u662f\u4e00\u6837\u3002\u73b0\u5728\u90e8\u7f72\u65f6\u4e0d\u62b1\u592a\u5927\u5e0c\u671b\u4e86\u5df2\u7ecf\u3002
  4. \n
  5. npm \u5305\u517c\u5bb9\u6027\u5dee\uff0c\u5f88\u591a\u91cd\u8981\u7684\u5305\u8981\u4e48\u517c\u5bb9\u5f97\u4e0d\u597d\uff0c\u8981\u4e48\u8bf4\u660e\u4e86\u4e0d\u4f1a\u517c\u5bb9\u3002\u8fd9\u91cc\u6bd4\u60f3\u8c61\u4e2d\u7684\u591a\u3002
  6. \n
  7. api \u53d8\u52a8\u5927\uff0c\u6bd4\u5982\u4e4b\u524d\u7528\u8fc7 bun serve \u505a http server \uff0c\u91cc\u9762\u6709\u4e2a fetch \u5199\u6cd5\uff0c\u91cc\u9762\u53ef\u4ee5\u81ea\u5df1\u5904\u7406\u8def\u7531\uff0c\u540e\u6765 1.2 \u51fa\u4e86\u81ea\u5e26\u8def\u7531\uff0c\u7ed3\u679c\u4e0d backward compatible \uff0c\u7528\u5c31\u5f97\u81ea\u5df1\u91cd\u6784\u3002\u3002\u3002
  8. \n
\n

\u4e00\u4e9b\u53ef\u4ee5\u79f0\u8d5e\u7684\u5730\u65b9

\n
    \n
  1. \u6587\u6863\u633a\u597d\uff0c\u7b80\u5355\u660e\u4e86
  2. \n
  3. api \u65b9\u4fbf\u5b9e\u7528\uff0c\u6bd4\u5982 Bun.password \uff0cBun.sql \uff0c\u7b49\u7b49\uff0c\u76f8\u6bd4\u7528 node \u7701\u4e86\u5f88\u591a\u4e09\u65b9\u5e93\u3002\uff08\u524d\u63d0\u662f\u80fd\u7a33\u5b9a\uff09
  4. \n
  5. \u6709\u524d\u7aef\u7684\u8bdd\uff0c\u81ea\u5e26 bundler \uff0c\u4e0d\u7528\u914d vite \u4ec0\u4e48\u7684\u3002\uff08\u524d\u63d0\u8fd8\u662f\u5f97\u7a33\u5b9a\uff0c\u8fd9\u4e2a\u529f\u80fd\u5728 linux \u73af\u5883\u6781\u5176\u4e0d\u7a33\u5b9a\uff0c\u57fa\u672c\u7528\u4e0d\u4e86\uff09
  6. \n
  7. bun add/install \u5feb\u4e00\u70b9
  8. \n
\n

\u603b\u7ed3\u5c31\u662f\uff0c\u8bbe\u8ba1\u5f97\u633a\u597d\uff0c\u6709\u60f3\u6cd5\u3002\u4f46\u662f\u5b9e\u9645\u505a\u5f97\u592a\u7cd9\uff0c\u54ea\u6015\u5c0f\u9879\u76ee\u90fd\u4e0d\u6562\u7528\u3002\u6700\u5f00\u59cb\u8212\u670d\u4e86\u4e00\u4e0b\uff0c\u73b0\u5728\u8fd8\u5f97\u8001\u8001\u5b9e\u5b9e\u6539\u56de node \u3002

\n", "date_published": "2025-05-14T02:18:10+00:00", "title": "\u5410\u69fd\u4e00\u4e0b bun", "id": "t/1131622" }, { "author": { "url": "member/iwannarocks", "name": "iwannarocks", "avatar": "https://cdn.v2ex.com/gravatar/a2cf87b393e6e091cc0bb91ae00c2e2f?s=73&d=retro" }, "url": "t/1130198", "title": "node.js \u6709\u4ec0\u4e48\u6bd4\u8f83\u597d\u7528\u7684\u5fae\u4fe1 sdk", "id": "t/1130198", "date_published": "2025-05-07T07:51:37+00:00", "content_html": "

\u627e\u4e86\u534a\u5929\uff0c\u90fd\u662f\u597d\u51e0\u5e74\u672a\u66f4\u65b0\u7684\u5e93\u4e86\u3002\u60f3\u5c1d\u8bd5\u7528 nest.js \u505a\u670d\u52a1\u7aef\uff0c\u9700\u8981\u5bf9\u63a5\u5fae\u4fe1\u7684\u5f00\u653e\u5e73\u53f0\uff0c\u5c0f\u7a0b\u5e8f\u516c\u5171\u53f7\u548c\u5fae\u4fe1\u652f\u4ed8\u3002\n\u5176\u4ed6\u8bed\u8a00\u90fd\u6709\u7b2c\u4e09\u65b9\u7ef4\u62a4\u7684\u5e93\uff0c\u4f46\u662f\u627e\u4e86\u4e00\u5708 node.js \u7684\u90fd\u662f\u597d\u4e45\u672a\u66f4\u65b0\u7684\uff0c\u5927\u5bb6\u90fd\u662f\u81ea\u5df1\u9020\u8f6e\u5b50\u4e48\uff1f

\n" }, { "author": { "url": "member/wuxilaoshiren", "name": "wuxilaoshiren", "avatar": "https://cdn.v2ex.com/gravatar/3073d603f7b00af33bc4ace2753c99f2?s=73&d=retro" }, "url": "t/1128871", "date_modified": "2025-04-30T00:54:39+00:00", "content_html": "

\u5404\u4f4d\u5728\u516c\u53f8\u91cc\u7684 nodejs \u540e\u7aef\u9879\u76ee\uff0c\u600e\u4e48\u751f\u6210\u7684\u63a5\u53e3\u6587\u6863\uff1f\u6392\u9664 nest.js \u548c jsdoc \u7684\u65b9\u5f0f\u3002

\n", "date_published": "2025-04-29T05:54:07+00:00", "title": "nodejs \u540e\u7aef\uff0c\u600e\u4e48\u6bd4\u8f83\u597d\u7684\u751f\u6210\u63a5\u53e3\u6587\u6863\uff1f(\u6392\u9664 nest.js)", "id": "t/1128871" }, { "author": { "url": "member/joynvda", "name": "joynvda", "avatar": "https://cdn.v2ex.com/avatar/eadb/bf17/502958_large.png?m=1621219620" }, "url": "t/1127639", "title": "Cherry Studio \u53ea\u7528 bun.exe \u600e\u4e48\u7ed5\u8fc7\u53bb\uff1f", "id": "t/1127639", "date_published": "2025-04-23T14:31:26+00:00", "content_html": "

\u4eca\u5929\u8981\u641e\u4e00\u4e2a Win Desktop Automation MCP \uff1b\u7528 github \u4e0a\u7684\u73b0\u6210\u4ee3\u7801\uff0cmcpinspector \u68c0\u6d4b\u4e5f\u6ca1\u95ee\u9898\u3002\n\u4f46\u662f,Cherry Studio \u5c31\u62a5\u9519\u3002Windsurf \u8ba4\u4e3a\u7684\u517c\u5bb9\u95ee\u9898\u3002

\n

\u65f6\u95f4\u539f\u56e0\u6ca1\u6cd5\u6162\u6162\u6392\u67e5\uff1b\u6682\u65f6\u6362 NextChat \u4e0a mcp \u3002

\n

\u5982\u679c\u5fc5\u987b\u8981\u7528 CherryStudio \uff0c\u4f46\u53c8\u4e0d\u60f3\u7528\u5185\u7f6e\u7684 bun \uff0c\u6709\u5565\u89e3\u51b3\u65b9\u6848\uff1f

\n" }, { "author": { "url": "member/songray", "name": "songray", "avatar": "https://cdn.v2ex.com/avatar/05c4/3b38/562248_large.png?m=1741416116" }, "url": "t/1125193", "date_modified": "2025-04-14T00:48:39+00:00", "content_html": "

https://github.com/Ray-D-Song/lexe

\n
\n

\u4e5f\u53ef\u4ee5\u4f7f\u7528 npx lexe build -i=index.js \u5feb\u901f\u4f53\u9a8c\u4e00\u4e0b

\n
\n

rt \uff0c\u5468\u672b\u5199\u7684\u5c0f\u73a9\u5177\uff0c\u9b54\u6539\u4e86 AWS \u7684 Javascript \u8fd0\u884c\u65f6 llrt \u3002
\nllrt \u63d0\u4f9b\u4e86\u5927\u591a\u6570\u5173\u952e\u7684 Node.js API \uff0c\u4f46\u56e0\u4e3a\u6ca1\u6709 JIT \uff0c\u6240\u4ee5\u8fd9\u4e2a\u5de5\u5177\u9002\u5408\u8f7b\u91cf\u7ea7\u670d\u52a1\u548c cli \u5de5\u5177\u3002

\n

\u5b9e\u73b0\u4e0a\u53c2\u8003\u4e86 deno compile \u548c bun compile \uff0c\u76ee\u524d\u4e00\u4e2a hello-world \u6253\u5305\u51fa\u6765\u662f 10M \uff0c\u867d\u7136\u8fd8\u53ef\u4ee5\u66f4\u5c0f\u4e00\u4e9b\uff0c\u4f46\u76f8\u8f83\u4e8e deno \u548c bun \u7684 50~60M \u5df2\u7ecf\u7b97\u53ef\u4ee5\u4e86\u3002

\n", "date_published": "2025-04-13T23:48:01+00:00", "title": "\u628a node.js \u7a0b\u5e8f\u6253\u5305\u6210\u53ef\u6267\u884c\u6587\u4ef6\uff0c\u4e0d\u8fc7\u53ea\u6709 10M", "id": "t/1125193" }, { "author": { "url": "member/cxhello", "name": "cxhello", "avatar": "https://cdn.v2ex.com/avatar/a0f8/5a7f/651579_large.png?m=1769489720" }, "url": "t/1122911", "title": "\u524d\u7aef\u5305\u7ba1\u7406\u5de5\u5177\u8c03\u7814", "id": "t/1122911", "date_published": "2025-04-02T09:13:43+00:00", "content_html": "\n

\u5404\u4f4d V \u53cb\u4eec\uff0c\u4f60\u4eec\u5728\u4f7f\u7528\u5305\u7ba1\u7406\u5de5\u5177\u6709\u4ec0\u4e48\u4f7f\u7528\u4f18\u5148\u7ea7\u5417\uff1f\u5b83\u4eec\u7684\u533a\u522b\u662f\u4ec0\u4e48\uff1f\u4f5c\u4e3a\u4e00\u4e2a\u540e\u7aef\uff0c\u6709\u65f6\u5019\u4f1a\u505a\u4e00\u4e9b\u524d\u7aef\u5f00\u53d1\uff0c\u4f1a\u7ea0\u7ed3\u8fd9\u4e9b\u3002\u867d\u7136\u662f\u778e\u7ea0\u7ed3\uff0c\u4f46\u8fd8\u662f\u60f3\u542c\u5404\u4f4d V \u53cb\u4eec\u8bb2\u8bb2\u3002

\n" }, { "author": { "url": "member/ChrisFreeMan", "name": "ChrisFreeMan", "avatar": "https://cdn.v2ex.com/avatar/f6c2/fb66/539019_large.png?m=1750398514" }, "url": "t/1122655", "date_modified": "2025-04-01T11:31:44+00:00", "content_html": "
// JS \u7684\u5185\u7f6e\u53d1\u5e03\u8ba2\u9605\n\n// create custom events\nconst catFound = new CustomEvent(\"animalfound\", {\n detail: {\n name: \"cat\",\n },\n});\nconst dogFound = new CustomEvent(\"animalfound\", {\n detail: {\n name: \"dog\",\n },\n});\n\nconst element = document.createElement(\"div\"); // create a <div> element\n\n// add an appropriate event listener\nelement.addEventListener(\"animalfound\", (e) => console.log(e.detail.name));\n\n// dispatch the events\nelement.dispatchEvent(catFound);\nelement.dispatchEvent(dogFound);\n\n// \"cat\" and \"dog\" logged in the console\n
\n
\n
// \u6211\u7684\u81ea\u5b9a\u4e49\u53d1\u5e03\u8ba2\u9605\uff0c\u6211\u7684\u684c\u9762\u5e94\u7528\u79fb\u52a8\u5e94\u7528\u7f51\u9875\u5e94\u7528\u90fd\u662f\u7528\u5b83\u9a71\u52a8\u7684\u3002\n\nexport class StateManage<T> {\n private inValue: T\n private publishChangeCalls: (() => void)[] = []\n\n constructor(v: T) {\n this.inValue = v\n }\n\n subscriptChange(subCall: () => void) {\n this.publishChangeCalls.push(subCall)\n }\n\n unsubscriptChange(subCall: () => void) {\n this.publishChangeCalls = this.publishChangeCalls.filter(sub => !Object.is(sub, subCall))\n }\n\n set value(v: T) {\n this.inValue = v\n this.publishChangeCalls.forEach(call => call())\n }\n\n get value(): T {\n return this.inValue\n }\n}\n
\n", "date_published": "2025-04-01T11:30:41+00:00", "title": "\u8bf7\u95ee\u4e0b Javascript \u7684 CustomEvent \u548c\u81ea\u5df1\u624b\u6413\u7684\u53d1\u5e03\u8ba2\u9605\u54ea\u4e2a\u66f4\u5feb\u6548\u7387\u66f4\u597d\uff1f", "id": "t/1122655" }, { "author": { "url": "member/jiaoguan1688", "name": "jiaoguan1688", "avatar": "https://cdn.v2ex.com/avatar/e043/056c/456168_large.png?m=1745522707" }, "url": "t/1122390", "date_modified": "2025-03-31T23:48:26+00:00", "content_html": "hbx \u57fa\u672c\u662f\u51e0\u79d2\u5c31\u597d
cursor \u6211\u770b\u8fdb\u5ea6\u5f88\u6162,\u5f97\u534a\u4e2a\u5c0f\u65f6
\u8fd9\u662f\u5565\u95ee\u9898\u5462", "date_published": "2025-03-31T12:43:24+00:00", "title": "\u540c\u6837\u662f\u8fd0\u884c npm run build \u6253\u5305\u7a0b\u5e8f cursor \u6bd4 hbx \u6162 1000 \u500d", "id": "t/1122390" }, { "author": { "url": "member/formulahendry", "name": "formulahendry", "avatar": "https://cdn.v2ex.com/avatar/9bd5/262e/205022_large.png?m=1677999975" }, "url": "t/1122153", "title": "\u4ece\u96f6\u5f00\u59cb\u5f00\u53d1\u4e00\u4e2a MCP Server\uff01", "id": "t/1122153", "date_published": "2025-03-31T00:02:24+00:00", "content_html": "

\u6700\u8fd1\uff0c\u5728 AI \u5f00\u53d1\u9886\u57df\uff0cMCP (Model Context Protocol) \u662f\u8d8a\u6765\u8d8a\u706b\u4e86\uff01

\n

\u524d\u51e0\u5929\uff0c\u6211\u6211\u4e5f\u5f00\u53d1\u4e86\u4e00\u6b3e Code Runner MCP Server\uff1a

\n

Code Runner MCP Server \uff0c\u652f\u6301\u8fd0\u884c 39 \u79cd\u7f16\u7a0b\u8bed\u8a00\uff01

\n

\u4eca\u5929\uff0c\u6211\u5c31\u628a\u6211\u5f00\u53d1 MCP Server \u7684\u7ecf\u9a8c\u548c\u9047\u5230\u7684\u4e00\u4e9b\u5751\uff0c\u5206\u4eab\u7ed9\u5927\u5bb6\uff01

\n

\u4ee5 Node.js \u4e3a\u4f8b\uff0c\u4ece\u96f6\u5f00\u59cb\u5f00\u53d1\u4e00\u4e2a MCP Server \uff01

\n

\u5b89\u88c5 Node.js

\n

\u4ece https://nodejs.org/en \u5b89\u88c5 LTS \u7248\u7684 Node.js \u5373\u53ef\u3002

\n

\u5b89\u88c5 Scaffolding Tool

\n

\u5728\u547d\u4ee4\u884c\u8fd0\u884c\u4e0b\u9762\u547d\u4ee4\uff0c\u5b89\u88c5 Yeoman Generator for MCP Server\uff1a

\n
npm install -g yo generator-mcp\n
\n

\u521b\u5efa MCP Server \u9879\u76ee

\n

\u5728\u547d\u4ee4\u884c\u8fd0\u884c\u4e0b\u9762\u547d\u4ee4\uff0c\u521b\u5efa MCP Server \u9879\u76ee\uff1a

\n
yo mcp -n 'Weather MCP Server'\n
\n

\u5b9e\u73b0\u4ee3\u7801\u903b\u8f91

\n

generator-mcp \u5df2\u7ecf\u628a\u5168\u90e8\u9700\u8981\u7684\u4ee3\u7801\u6846\u67b6\u548c\u4f9d\u8d56\u90fd\u751f\u6210\u548c\u5b89\u88c5\u4e86\u3002

\n

\u4f60\u53ef\u4ee5\u6309\u9700\u4fee\u6539\u4ee3\u7801\uff0c\u6216\u8005\u5229\u7528\u5df2\u6709\u7684\u4ee3\u7801\u76f4\u63a5\u8fdb\u884c\u8c03\u8bd5\u548c\u6d4b\u8bd5\u3002

\n

\u8c03\u8bd5/\u6d4b\u8bd5

\n

generator-mcp \u5df2\u7ecf\u914d\u7f6e\u597d\u4e86 VS Code \u7684\u8c03\u8bd5\u914d\u7f6e\u6587\u4ef6\uff1alaunch.json \u548c tasks.json

\n

\u5728 VS Code \u4e2d\u6253\u5f00\u9879\u76ee\uff0c\u6309 F5 \u5c31\u80fd\u4e00\u952e\u542f\u52a8\u8c03\u8bd5\uff01

\n

\u7a0d\u7b49\u7247\u523b\uff0c\u6d4f\u89c8\u5668\u81ea\u52a8\u6253\u5f00 MCP Inspector \u540e\uff0c\u5c31\u80fd\u8fdb\u884c\u6d4b\u8bd5\u4e86\uff01

\n

\"\"

\n

\u8fd0\u884c

\n

\u6b64\u5916\uff0c\u4f60\u8fd8\u53ef\u4ee5\u5728\u5176\u4ed6\u652f\u6301 MCP \u7684\u5ba2\u6237\u7aef\u4e2d\uff0c\u6d4b\u8bd5\u4f60\u7684 MCP Server \u3002

\n

generator-mcp \u5df2\u7ecf\u9ed8\u8ba4\u521b\u5efa\u4e86 .vscode\\mcp.json \u6587\u4ef6\uff0c\u8fd9\u4e2a\u6587\u4ef6\u5b9a\u4e49\u4e86\u5728 VS Code \u8fd0\u884c\u7684 MCP Server \u3002

\n

\"\"

\n

\u6ce8\uff1a\u9700\u4ece https://code.visualstudio.com/insiders/ \u4e0b\u8f7d\u6700\u65b0\u7248\u672c\u7684 VS Code Insiders \u3002

\n

\u5b89\u88c5\u597d\u6700\u65b0\u7684 VS Code Insiders \u7248\u672c\uff0c\u70b9\u51fb \u201cstart\u201d \u6309\u94ae\uff0c\u5c31\u80fd\u5728 VS Code Insiders \u7684 Agent Mode \u8c03\u7528\u4f60\u7684 MCP Server \u5566\uff01

\n

\"\"

\n

\"\"

\n

\u53d1\u5e03

\n

\u6d4b\u8bd5\u5b8c\u6210\u540e\uff0c\u5c31\u53ef\u4ee5\u628a\u4f60\u7684 MCP Server \u53d1\u5e03\u5230 npm registry \u6216\u8005 Docker Hub \u4e86\uff01

\n

\u5173\u4e8e Dockerfile \u600e\u4e48\u5199\uff0c\u4ee5\u53ca\u5982\u4f55\u5728 VS Code \u3001Claude Desktop \u7b49\u5ba2\u6237\u7aef\u914d\u7f6e MCP Server \uff0c\u8fd8\u6709 npx \u53ef\u80fd\u5728 Windows \u4e0a\u8fd0\u884c\u5931\u8d25\u7684\u95ee\u9898\uff0c\u90fd\u53ef\u4ee5\u53c2\u8003 Code Runner MCP Server \u7684 README \u548c\u6e90\u4ee3\u7801\uff0c\u5b8c\u5168\u5f00\u6e90\uff1a

\n

https://github.com/formulahendry/mcp-server-code-runner

\n" }, { "author": { "url": "member/elixirchina", "name": "elixirchina", "avatar": "https://cdn.v2ex.com/avatar/d2ea/a965/578251_large.png?m=1694239149" }, "url": "t/1120699", "title": "\u73b0\u5728\u8fd8\u6709\u4eba eggjs \u5417\uff1f", "id": "t/1120699", "date_published": "2025-03-24T07:05:10+00:00", "content_html": "

\u5982\u9898\uff0c\u6b7b\u53bb\u7684\u56de\u53bb\u5f00\u59cb\u653b\u51fb\u6211\uff0c\u53ea\u662f\u597d\u5947\u73b0\u5728\u8fd8\u6709\u4eba\u7528 eggjs \u5417\uff1f\n\u672c\u4eba 21 \u5e74\u7684\u65f6\u5019\u77ed\u6682\u7684\u4f7f\u7528\u8fc7\u4e00\u6bb5\u65f6\u95f4

\n" }, { "author": { "url": "member/ChrisFreeMan", "name": "ChrisFreeMan", "avatar": "https://cdn.v2ex.com/avatar/f6c2/fb66/539019_large.png?m=1750398514" }, "url": "t/1117710", "title": "TypeScript7.0 \u7528 go \u91cd\u5199\uff0c 10 \u500d\u5feb\uff0c\u770b\u4e86\u4e24\u904d\u786e\u5b9a\u662f\u771f\u7684...", "id": "t/1117710", "date_published": "2025-03-11T16:14:00+00:00", "content_html": "

https://devblogs.microsoft.com/typescript/typescript-native-port/

\n

github: https://github.com/microsoft/typescript-go

\n" }, { "author": { "url": "member/pickknow", "name": "pickknow", "avatar": "https://cdn.v2ex.com/gravatar/7bd019d1acfc41b87c33d75dd62cdd62?s=73&d=retro" }, "url": "t/1115593", "title": "\u505a\u4e86\u51e0\u4e2a\u6269\u5c55\uff0c\u987a\u4fbf\u6574\u7406\u4e86\u4e00\u4e0b\u5f00\u6e90\u4e86\u4e00\u4e2a\u6d4f\u89c8\u5668\u6269\u5c55\u5f00\u53d1\u6a21\u7248", "id": "t/1115593", "date_published": "2025-03-03T10:59:22+00:00", "content_html": "

\u6700\u8fd1\u505a\u4e86\u51e0\u4e2a\u6d4f\u89c8\u5668\u7684\u6269\u5c55\uff0c\u987a\u4fbf\u628a\u4ee3\u7801\u6574\u7406\u4e86\u4e00\u4e0b\u505a\u4e86\u4e2a\u6a21\u7248\uff0c\u5f00\u7bb1\u5373\u7528\uff0c\u76f4\u63a5\u5199\u903b\u8f91\uff0c\u4e0d\u7528\u914d\u7f6e\u4e86

\n

\u4ed3\u5e93\u5730\u5740 https://github.com/pickknow/chrome-extension-react-Tailwindcss-typescript\nReact\nTypeScript\nTailwind CSS\nWebpack\nChrome Extension APIs\nDaisyUI

\n

bookmark tagger\nhttps://chromewebstore.google.com/detail/bookmark-tagger/eibebfbmnojbnbadhhcnnioocejgfmpg?authuser=0&hl=en\n\u4e00\u4e2a\u6dfb\u52a0\u4e66\u7b7e\u7684\u65f6\u5019\u53ef\u4ee5\u4f7f\u7528\u591a\u6807\u7b7e\u7684\u6269\u5c55\uff0c

\n" }, { "author": { "url": "member/yagamil", "name": "yagamil", "avatar": "https://cdn.v2ex.com/gravatar/26595a3b82bcd82eee336675814ce135?s=73&d=retro" }, "url": "t/1115199", "title": "prisma \u8fd0\u884c migrate \u547d\u4ee4\u4e4b\u540e\uff0c\u603b\u4f1a\u628a\u5176\u4ed6\u4e0d\u76f8\u5173\u7684\u8868\u7ed9\u5220\u9664", "id": "t/1115199", "date_published": "2025-03-02T02:52:21+00:00", "content_html": "\u56e0\u4e3a\u8fd9\u4e2a db \u4e0b\u6709\u5176\u4ed6\u7684\u4e34\u65f6\u8868\uff0c\u548c\u5f53\u524d\u9879\u76ee\u65e0\u5173\uff0c\u6d4b\u8bd5\u65f6\u53d1\u73b0\uff0c\u8fd0\u884c\u8fc1\u79fb\u547d\u4ee4\u7684\u65f6\u5019\uff0c\u4ed6\u4f1a\u628a\u6211\u5176\u4ed6\u7684\u8868\u7ed9\u5220\u6389\uff0c
\u6709\u4ec0\u4e48\u529e\u6cd5\u53ef\u4ee5\u53ea\u65b0\u589e\u8868\u548c\u4fee\u6539\u8868\uff0c\u4e0d\u52a8\u4e0d\u76f8\u5173\u7684\u8868\u7684\uff1f
\u95ee gpt \uff0c\u90fd\u8bf4\u53ef\u4ee5\u4fee\u6539 migration \u76ee\u5f55\u7684 sql \u6587\u4ef6\uff0c\u4f46\u8fd9\u4e2a\u6587\u4ef6\u4e0b\u4e5f\u53ea\u6709\u5efa\u8868\uff0c\u66f4\u6539\u8868\u7684 sql \u8bed\u53e5\uff0c\u5e76\u6ca1\u6709\u5220\u8868\u7684\u8bed\u53e5" }, { "author": { "url": "member/guoguobaba", "name": "guoguobaba", "avatar": "https://cdn.v2ex.com/avatar/48a4/7fbb/307012_large.png?m=1742526918" }, "url": "t/1115066", "title": "\u95ee\u4e2a\u9875\u9762\u8df3\u8f6c\u8bbf\u95ee\u65b9\u6848", "id": "t/1115066", "date_published": "2025-03-01T05:10:51+00:00", "content_html": "

\u5e2e\u670b\u53cb\u914d\u4e86\u53f0 openwrt \u8def\u7531\u5668\uff0c\u7136\u540e\u5f04\u4e86\u4e2a\u57df\u540d\uff0c\u5728 cf \u4e0a\u53d1\u5e03\u4e86\u4e00\u4e2a\u673a\u573a\u805a\u5408\u8ba2\u9605\uff0c\u7c7b\u4f3c\u4e8e https://fgfw.xxx.com/xxx \uff0c\u653e\u5230\u5b83 openclash \u8ba2\u9605 url \u91cc

\n

\u9996\u5148\u8fd9\u4e2a\u57df\u540d\u662f\u6700\u4fbf\u5b9c\u7684\u90a3\u79cd\uff0c\u4e00\u5e74 8 \u5757\u94b1\uff0c\u7eed\u8d39\u5c31\u6bd4\u8f83\u8d35\u4e86\uff0c\u6240\u4ee5\u6211\u6253\u7b97\u6bcf\u5e74\u6362\u4e2a\u57df\u540d\u3002\u4f46\u662f\u6362\u4e86\u4e4b\u540e\u5c31\u5f97\u53bb\u5e2e\u4ed6\u4fee\u6539\u8ba2\u9605\uff0c\u5f88\u9ebb\u70e6\u3002

\n

\u6240\u4ee5\u6211\u60f3\u4e86\u4e2a\u65b9\u6848\uff0c\u5c31\u662f\u627e\u4e00\u4e2a\u652f\u6301 redirect \u7684\u514d\u8d39\u670d\u52a1\uff0c\u7c7b\u4f3c\u4e8e xxx.github.io \uff0c\u90e8\u7f72\u4e00\u4e0b redirect url \u7684\u670d\u52a1\uff0c\u7c7b\u4f3c\u4e8e

\n
<!DOCTYPE html>\n<html>\n<head>\n <meta http-equiv=\"refresh\" cOntent=\"0;url=https://fgfw.xxx.com\">\n <title>301 Moved Permanently</title>\n</head>\n<body>\n</body>\n</html>\n
\n

\u6211\u628a\u8ba2\u9605 url \u6539\u6210 https://xxx.github.io/index.html \u5c31\u884c\u4e86\u3002\u4ee5\u540e\u6362\u57df\u540d\u4e86\uff0c\u6211\u4fee\u6539 github \u7684\u914d\u7f6e\u5c31\u884c\u4e86\u3002\u8def\u7531\u5668\u90a3\u8fb9\u4e0d\u7528\u52a8\u3002

\n

\u4f46\u662f\u53d1\u73b0 openclash \u662f\u901a\u8fc7 curl \u4e0b\u8f7d\u8ba2\u9605\u7684\uff0c\u800c github pages \u4e0d\u652f\u6301 301 \u8df3\u8f6c\u3002

\n

\u8fd9\u8ba9\u6211\u60f3\u627e\u4e00\u4e2a\u652f\u6301 node js server \u7684\u7ad9\u70b9\uff0c\u5c31\u53c8\u56de\u5230\u9e21\u751f\u86cb\u86cb\u751f\u9e21\u7684\u95ee\u9898\u4e86\uff0ccf worker \u5c31\u662f\u5e72\u8fd9\u4e2a\uff0c\u4f46\u662f\u5b83\u7ed9\u6211\u7684\u7f3a\u7701\u57df\u540d\u88ab\u5899\u4e86\uff0cvercel \u4e5f\u662f\u5982\u6b64\u3002

\n

\u6240\u4ee5\u6211\u9700\u8981\u4e00\u4e2a\u80fd\u591f redirect \u6211 url \u7684\u670d\u52a1\uff0c\u80fd\u63d0\u4f9b\u514d\u8d39\u57df\u540d\uff0c\u7c7b\u4f3c xxx.github.io \uff0c\u6700\u597d\u6bd4\u8f83\u575a\u633a\uff0c\u6bd4\u6211\u7684\u57df\u540d\u5b58\u6d3b\u65f6\u95f4\u957f\u3002

\n" }, { "author": { "url": "member/sweetliu666", "name": "sweetliu666", "avatar": "https://cdn.v2ex.com/gravatar/9625f2baa068b9305bcc1de10398dd62?s=73&d=retro" }, "url": "t/1112560", "date_modified": "2025-02-20T02:37:09+00:00", "content_html": "\u5982\u9898\uff0c\u6c42\u5404\u4f4d v \u53cb\u63a8\u8350\u9760\u8c31\u7684 node.js \u5b66\u4e60\u7f51\u7ad9\u548c\u89c6\u9891\uff0c\u5982\u679c\u6709\u5173\u4e8e node.js \u9762\u8bd5\u7684\u9760\u8c31\u7f51\u7ad9\uff0c\u4e5f\u8bf7\u5927\u5bb6\u63a8\u8350\u4e0b\u3002\u8c22\u8c22~", "date_published": "2025-02-19T02:57:54+00:00", "title": "\u6c42\u52a9\uff01 v \u53cb\u4eec\u6c42\u63a8\u8350\u9760\u8c31\u7684 node.js \u5b66\u4e60\u53ca\u9762\u8bd5\u7f51\u7ad9\u548c\u89c6\u9891", "id": "t/1112560" }, { "author": { "url": "member/nyse", "name": "nyse", "avatar": "https://cdn.v2ex.com/avatar/07f7/4922/254964_large.png?m=1534388066" }, "url": "t/1111326", "title": "\u5927\u5bb6\u6b63\u4f7f\u7528\u54ea\u4e2a node \u7248\u672c\uff0c\u4f1a\u4fdd\u6301\u7528\u6700\u65b0\u7248\u5417\uff1f", "id": "t/1111326", "date_published": "2025-02-13T16:36:41+00:00", "content_html": "

\u66f4\u65b0\u4f9d\u8d56\u65f6\u63d0\u793a node \u7248\u672c\u8fc7\u65e7\uff0c\u770b\u4e86\u4e00\u4e0b\uff0c\u6211\u7528\u7684 20.x \u4e5f\u4e0d\u7b97\u65e7\u5427\u3002

\n

\u7136\u540e\u767b\u9646\u5b98\u7f51\u770b\u4e86\u4e00\u4e0b\uff0c\u76ee\u524d LTS \u662f 22.x

\n

\u60f3\u95ee\u5927\u5bb6\u5e73\u65f6\u4f1a\u4fdd\u6301\u7528\u6700\u65b0\u7248\u7684 node \u5417\uff1f

\n

\u4e00\u822c\u662f\u4ec0\u4e48\u65f6\u5019\u4f1a\u8fdb\u884c\u5927\u7248\u672c\u66f4\u65b0\u7684\uff1f

\n" }, { "author": { "url": "member/Belmode", "name": "Belmode", "avatar": "https://cdn.v2ex.com/avatar/58c3/16c0/312499_large.png?m=1748572228" }, "url": "t/1110759", "date_modified": "2025-02-11T12:38:14+00:00", "content_html": "

\u6211\u73b0\u5728\u60f3\u5728 node.js \u5e73\u53f0\u4e0a\u4f7f\u7528 hono.js \uff0c\u73b0\u5728\u9700\u8981\u5b9e\u73b0\u4e00\u4e2a\u6587\u4ef6\u4e0b\u8f7d\u9700\u6c42

\n
\n //\u51e0\u4e2a\u7c7b\u578b\u5bfc\u5165\uff1a\n import { stream } from \"hono/streaming\"\n import { Readable, Writable } from \"node:stream\"\n import { ReadableStream } from \"node:stream/web\"\n\n\t// ......\n const fileStream = createReadStream(filePath)\n // \u5c06\u6587\u4ef6\u6d41\u4f5c\u4e3a\u54cd\u5e94\u8fd4\u56de\u7ed9\u5ba2\u6237\u7aef\n return stream(\n c,\n async (stream) => {\n // Write a process to be executed when aborted.\n stream.onAbort(() => {\n console.log('Aborted!')\n })\n // Write a Uint8Array.\n await stream.write(\n new Uint8Array([0x48, 0x65, 0x6c, 0x6c, 0x6f])\n )\n // Pipe a readable stream.\n // \u8fd9\u91cc\u51fa\u73b0\u4e86\u7c7b\u578b\u4e0d\u517c\u5bb9\n // await stream.pipe(Readable.toWeb(fileStream))\n await stream.pipe(ReadableStream.from(fileStream))\n },\n async (err, stream) => {\n // stream.writeln('An error occurred!')\n console.error('An error occurred!', err)\n }\n )\n
\n
\n

ts \u63d0\u793a\uff1a\n\u7c7b\u578b\u201cimport(\"stream/web\").ReadableStream<any>\u201d\u7684\u53c2\u6570\u4e0d\u80fd\u8d4b\u7ed9\u7c7b\u578b\u201cReadableStream<any>\u201d\u7684\u53c2\u6570.\n\u5c5e\u6027\u201cpipeThrough\u201d\u7684\u7c7b\u578b\u4e0d\u517c\u5bb9\u3002

\n
\n

\u6211\u8be5\u5982\u4f55\u89e3\u51b3\uff0c\u6216\u8005\u8bf4\u5982\u4f55\u5728 nodejs \u73af\u5883\u4f7f\u7528...

\n

\u8c22\u8c22\u5927\u5bb6\u4e86\uff01\ud83d\ude47\u200d\ud83d\ude18

\n", "date_published": "2025-02-11T12:31:00+00:00", "title": "\u8bf7\u6559\u5927\u5bb6\u4e00\u4e2a\u5728 hono.js \u4e2d\u4f7f\u7528 ts \u7684\u7c7b\u578b\u517c\u5bb9\u6027\u95ee\u9898", "id": "t/1110759" } ] } ubao msn snddm index pchome yahoo rakuten mypaper meadowduck bidyahoo youbao zxmzxm asda bnvcg cvbfg dfscv mmhjk xxddc yybgb zznbn ccubao uaitu acv GXCV ET GDG YH FG BCVB FJFH CBRE CBC GDG ET54 WRWR RWER WREW WRWER RWER SDG EW SF DSFSF fbbs ubao fhd dfg ewr dg df ewwr ewwr et ruyut utut dfg fgd gdfgt etg dfgt dfgd ert4 gd fgg wr 235 wer3 we vsdf sdf gdf ert xcv sdf rwer hfd dfg cvb rwf afb dfh jgh bmn lgh rty gfds cxv xcv xcs vdas fdf fgd cv sdf tert sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf shasha9178 shasha9178 shasha9178 shasha9178 shasha9178 liflif2 liflif2 liflif2 liflif2 liflif2 liblib3 liblib3 liblib3 liblib3 liblib3 zhazha444 zhazha444 zhazha444 zhazha444 zhazha444 dende5 dende denden denden2 denden21 fenfen9 fenf619 fen619 fenfe9 fe619 sdf sdf sdf sdf sdf zhazh90 zhazh0 zhaa50 zha90 zh590 zho zhoz zhozh zhozho zhozho2 lislis lls95 lili95 lils5 liss9 sdf0ty987 sdft876 sdft9876 sdf09876 sd0t9876 sdf0ty98 sdf0976 sdf0ty986 sdf0ty96 sdf0t76 sdf0876 df0ty98 sf0t876 sd0ty76 sdy76 sdf76 sdf0t76 sdf0ty9 sdf0ty98 sdf0ty987 sdf0ty98 sdf6676 sdf876 sd876 sd876 sdf6 sdf6 sdf9876 sdf0t sdf06 sdf0ty9776 sdf0ty9776 sdf0ty76 sdf8876 sdf0t sd6 sdf06 s688876 sd688 sdf86