Express项目配置文件提前加载致Env变量未定义的无重复dotenv解决方法
问题:Socket配置文件提前加载导致环境变量未定义
在Express项目中,server.ts是入口文件,app.ts中调用dotenv.config()加载环境变量,但config/socket-config.ts的顶级代码在app.ts之前执行,导致process.env.WHITELIST_ORIGINS为undefined,希望找到无需在socket-config中重复调用dotenv的解决办法。
相关代码
server.ts
import http from 'http' import { Socket } from 'socket.io' import app from './app' import { setIO } from './config' const server = http.createServer(app) const io = setIO(server) io.on('connection', function (socket: Socket) { console.log('New client connected with id => ', socket.id) socket.on('disconnect', function (reason): void { console.log('A client disconnected with id => ', socket.id, ' reason => ', reason) }) }) const port = process.env.PORT || 8095 server.listen(port, () => { console.log(`App running`) }) console.log('server call')
app.ts
import compression from 'compression' import cors from 'cors' import dotenv from 'dotenv' import express, { Application } from 'express' import helmet from 'helmet' import { errorHandler, verifyToken } from './middleware' import router from './router' dotenv.config() const app: Application = express() app.use(compression()) app.use(cors()) app.use(express.json()) app.use(express.urlencoded({ extended: true })) app.use(helmet()) app.use(verifyToken) app.use('/', router) app.use(errorHandler) console.log('app call') export default app
config/socket-config.ts
import { Server as HttpServer } from 'http' import { Server } from 'socket.io' // import dotenv from 'dotenv' // dotenv.config() - 如果在这里调用就能正常工作 let _io: Server const whitelistOrigins = process.env.WHITELIST_ORIGINS console.log("whitelistOrigins", whitelistOrigins) // 这里输出undefined console.log('socket call') export const setIO = (server: HttpServer): Server => { _io = new Server(server, { cors: { origin: whitelistOrigins, methods: ['GET', 'POST'], credentials: true, }, allowEIO3: true, }) return _io } export const getIO = () => { return _io }
控制台日志顺序
whitelistOrigins undefined socket call app call server call App running
原因分析
ES模块采用静态解析加载机制:当server.ts导入./app和./config时,Node.js会优先加载所有被导入的模块,执行它们的顶级代码(即函数外部的代码)。socket-config.ts里的const whitelistOrigins = process.env.WHITELIST_ORIGINS和控制台打印代码,会在app.ts中的dotenv.config()执行前就运行,此时环境变量还未被初始化,所以变量值为undefined。
解决方案
方案1:将dotenv调用移到入口文件最顶部
修改server.ts,在所有模块导入前先初始化dotenv,确保所有模块加载时环境变量已就绪:
// server.ts 最顶部 import dotenv from 'dotenv' dotenv.config() // 后续导入其他模块 import http from 'http' import { Socket } from 'socket.io' import app from './app' import { setIO } from './config' // ... 剩余代码保持不变
方案2:延迟环境变量的获取到函数内部
修改socket-config.ts,把环境变量的获取逻辑移到setIO函数内部,利用函数调用时机确保环境变量已加载:
import { Server as HttpServer } from 'http' import { Server } from 'socket.io' let _io: Server export const setIO = (server: HttpServer): Server => { // 在这里获取环境变量,此时app.ts已执行dotenv.config() const whitelistOrigins = process.env.WHITELIST_ORIGINS console.log("whitelistOrigins", whitelistOrigins) _io = new Server(server, { cors: { origin: whitelistOrigins, methods: ['GET', 'POST'], credentials: true, }, allowEIO3: true, }) return _io } export const getIO = () => { return _io } console.log('socket call')
内容的提问来源于stack exchange,提问作者paperskyline
相关产品推荐
相关产品推荐

