如何在fastify-cli创建的TypeScript项目中显式覆盖服务器端口?
解决Fastify-CLI创建的TypeScript项目中PORT环境变量不生效的问题
问题背景
我用fastify-cli创建了TypeScript项目,app.ts以插件形式初始化,代码如下:
import './pre-start'; import { join } from 'path'; import AutoLoad, {AutoloadPluginOptions} from '@fastify/autoload'; import { FastifyPluginAsync } from 'fastify'; export type AppOptions = { // Place your custom options for app below here. } & Partial<AutoloadPluginOptions>; // Pass --options via CLI arguments in command to enable these options. const options: AppOptions = { } const app: FastifyPluginAsync<AppOptions> = async ( fastify, opts ): Promise<void> => { // Place here your custom code! // Do not touch the following lines // This loads all plugins defined in plugins // those should be support plugins that are reused // through your application void fastify.register(AutoLoad, { dir: join(__dirname, 'plugins'), options: opts }) // This loads all plugins defined in routes // define your routes in one of these void fastify.register(AutoLoad, { dir: join(__dirname, 'routes'), options: opts }) }; export default app; export { app, options }
该文件没有服务器监听逻辑,无法在代码中显式指定端口。我沿用Express项目的习惯,通过./pre-start.ts用dotenv加载对应环境的.env文件(development.env、test.env、production.env):
import path from 'path'; import dotenv from 'dotenv'; import commandLineArgs from 'command-line-args'; const options = commandLineArgs([ { name: 'env', alias: 'e', defaultValue: 'development', type: String, }, ]); const result2 = dotenv.config({ path: path.join(__dirname, `../env/${String(options.env)}.env`), }); if (result2.error) { throw result2.error; }
虽然在app.ts作用域内能读到正确的PORT环境变量,但启动项目时Fastify仍使用默认的3000端口,完全忽略该配置。当前npm命令配置如下:
{ "scripts": { "test": "npm run build:ts && tsc -p test/tsconfig.json && tap --ts \"test/**/*.test.ts\"", "start": "npm run build:ts && fastify start -l info dist/app.js", "build:ts": "tsc", "watch:ts": "tsc -w", "dev": "npm run build:ts && concurrently -k -p \"[{name}]\" -n \"TypeScript,App\" -c \"yellow.bold,cyan.bold\" \"npm:watch:ts\" \"npm:dev:start\"", "dev:start": "fastify start --ignore-watch=.ts$ -w -l info -P dist/app.js" }, }
解决方案
方案一:在启动命令中直接指定端口
fastify-cli的start命令支持通过--port(或缩写-p)参数指定端口,可将环境变量直接嵌入npm脚本:
修改package.json的scripts:
{ "start": "npm run build:ts && fastify start -l info -p $PORT dist/app.js", "dev:start": "fastify start --ignore-watch=.ts$ -w -l info -P -p $PORT dist/app.js" }
跨平台兼容说明:Windows环境需改用%PORT%,若要同时支持Windows和类Unix系统,可先安装cross-env依赖:
npm install cross-env --save-dev
再修改脚本:
{ "start": "cross-env npm run build:ts && fastify start -l info -p $PORT dist/app.js", "dev:start": "cross-env fastify start --ignore-watch=.ts$ -w -l info -P -p $PORT dist/app.js" }
方案二:修改app.ts的options配置注入端口
fastify-cli启动时会读取app.ts导出的options对象,可在此直接传入PORT环境变量:
修改app.ts中的options对象:
const options: AppOptions = { port: Number(process.env.PORT) || 3000 }
这样fastify-cli启动时会自动使用该端口配置,无需修改命令行参数。
方案三:绕过fastify-cli,手动创建启动文件
若想完全掌控启动流程,可新建server.ts文件,手动初始化Fastify并监听端口:
import './pre-start'; import fastify from 'fastify'; import app from './app'; const server = fastify({ logger: { level: 'info' } }); async function start() { try { await server.register(app); const port = Number(process.env.PORT) || 3000; await server.listen({ port }); console.log(`Server running on port ${port}`); } catch (err) { server.log.error(err); process.exit(1); } } start();
然后修改package.json的scripts,直接运行该文件:
{ "start": "npm run build:ts && node dist/server.js", "dev:start": "nodemon dist/server.js" }
这种方式更贴近Express的启动模式,完全由开发者控制服务器的初始化和监听逻辑。
内容的提问来源于stack exchange,提问作者Ian Gopfert
相关产品推荐
相关产品推荐

