Node v16.6.0环境下Nodemon提示应用崩溃,求排查方案
问题描述
我的环境:Node.js v16.6.0、NPM v8.5.0
运行项目时Nodemon提示:Nodemon: app crashed waiting for file changes before starting
已尝试通过Windows任务管理器结束Node.js JavaScript Runtime进程,但问题未解决。
以下是server.js代码:
import * as express from 'express'; import * as bodyParser from 'body-parser'; import 'reflect-metadata'; import * as cors from 'cors'; import * as swaggerUi from 'swagger-ui-express'; import * as swaggerJSDoc from 'swagger-jsdoc'; import * as lodash from 'lodash'; import * as path from 'path'; import * as fs from 'fs'; import * as logger from 'morgan'; import * as dotenv from 'dotenv'; import * as http from 'http'; import * as AgendaInstance from 'agenda'; import * as AgendashInstance from 'agendash'; import initGlobalVariables from './constants'; import HttpResponse from './services/response'; import CustomResponse from './services/response/customResponse'; import * as logrotate from 'logrotator'; import Agenda from './services/agenda'; // Import passport strategies import passportStrategies from './config/passport'; import {helpers} from './utils'; /** Rotation is based on copying the file contents and then truncating the file size to 0. * This way we avoid file renaming problems where programs are not always prepared to handle a log file being renamed. */ const rotator = logrotate.rotator; // Load environment variables from .env file dotenv.config(); (async () => { // Init global variables await initGlobalVariables(); // Create Express server const app = express(); // Express configuration app.all('/*', function (req, res, next) { res.header('Access-Control-Allow-Origin', '*'); next(); }); // Request body parser app.use(bodyParser.json()); app.use(bodyParser.urlencoded({extended: true})); // Enable CORS app.use(cors()); // Middleware to check tenant code // app.use(async (req, res, next) => { // let tenantCode = req.get('code'); // if (tenantCode) { // // Update current connection by the new one // // NOTE THAT SWITCHING TENANT DB WILL AFFECT TO ALL REQUEST FROM NOW ON // await global.mongoInstances['default'].updateCurrentConnectionByTenantCode( // tenantCode, global.connections['default']); // // Re init model base on the new connection // global.mongoModel = initModel(global.connections.currentTenantConnection); // } // next(); // }); // Import public routers const initPublicRouter = await import('./routes'); initPublicRouter(app); // Set template engine app.set('views', 'src/views'); app.set('view engine', 'hbs'); /*/////////////////////////////////////////////////////////////// ///// START LOGS CONFIG ///// ///////////////////////////////////////////////////////////////*/ // For production, access logs keep all logs about http requests, including error logs if (process.env.NODE_ENV === 'development') { // Create log directory const logDirectory = path.resolve('logs'); fs.existsSync(logDirectory) || fs.mkdirSync(logDirectory); // Define directory to write access logs const logPath = path.join(process.cwd(), '/logs/access.log'); const accessLogStream = fs.createWriteStream(logPath, {flags: 'a'}); app.use(logger('combined', {stream: accessLogStream})); // Check file rotation every 30 minutes, and rotate the file if its size exceeds 10 mb. // Keep only 3 rotated files and compress (gzip) them. rotator.register(logPath, {schedule: '30m', size: '10m', compress: true, count: 3}); rotator.on('error', function (err) { logger('Oops, an error occured!'); }); // 'rotate' event is invoked whenever a registered file gets rotated rotator.on('rotate', function (file) { logger('File ' + file + ' was rotated!'); }); } // Show method, url, status , response time, res content length in console log app.use(logger('dev')); /*/////////////////////////////////////////////////////////////// ///// END LOGS CONFIG ///// ///////////////////////////////////////////////////////////////*/ /*/////////////////////////////////////////////////////////////// ///// START SWAGGER CONFIG ///// ///////////////////////////////////////////////////////////////*/ const swaggerDefinition = { info: { // API informations (required) title: 'Home Key APIs', // Title (required) version: '1.0.0', // Version (required) }, basePath: '/api', // Base path (optional), securityDefinitions: { // Enable api key in header, using security: - auth: [] in jsdoc to enable check this auth: { type: 'apiKey', in: 'header', name: 'Authorization', }, }, }; const filenameExtension = process.env.NODE_ENV === 'local' ? 'ts' : 'js'; const basePath = process.env.NODE_ENV === 'local' ? './src/' : './build/'; const lookupFolders = [path.join(basePath, 'controllers'), path.join(basePath, 'models')]; let swaggerApis = []; //General path to lookup swagger define lodash.forEach(lookupFolders, lookupFolder => { const directories = helpers.getDirectories(lookupFolder); lodash.forEach(directories, directory => { swaggerApis.push(path.join(directory, `*.${filenameExtension}`)); }); }); let options = { swaggerDefinition, apis: swaggerApis, // <-- not in the definition, but in the options }; const swaggerSpec = swaggerJSDoc(options); app.use('/api-docs', swaggerUi.serve, swaggerUi.setup(swaggerSpec)); /*/////////////////////////////////////////////////////////////// ///// END SWAGGER CONFIG ///// ///////////////////////////////////////////////////////////////*/ /*/////////////////////////////////////////////////////////////// ///// START AGENDA DASHBOARD CONFIG ///// ///////////////////////////////////////////////////////////////*/ // Init agenda instance const agenda = new AgendaInstance({ db: { address: global.configs.agenda.dbUri, collection: 'scheduleJobs', options: { useNewUrlParser: true, }, }, }); // Serve agenda dashboard app.use('/agenda/dashboard', AgendashInstance(agenda)); /*/////////////////////////////////////////////////////////////// ///// END AGENDA DASHBOARD CONFIG ///// ///////////////////////////////////////////////////////////////*/ // Init Passport passportStrategies(app); /*/////////////////////////////////////////////////////////////// ///// START CORS MIDDLEWARE ///// ///////////////////////////////////////////////////////////////*/ app.use(function (req, res, next) { let value = req.get('referer'); if (!value) { value = req.get('origin'); } res.header('Access-Control-Allow-Credentials', 'true'); res.header('Access-Control-Allow-Methods', 'GET,PUT,POST,DELETE'); res.header( 'Access-Control-Allow-Headers', 'Origin, Content-Type, Authorization, REST-API-KEY-HEADER, x-auth-token, switch-company-code', ); // intercept OPTIONS method if ('OPTIONS' === req.method) { res.sendStatus(200); } else { next(); } }); /*/////////////////////////////////////////////////////////////// ///// END CORS MIDDLEWARE ///// ///////////////////////////////////////////////////////////////*/ /*/////////////////////////////////////////////////////////////// ///// START STATIC PATH ///// ///////////////////////////////////////////////////////////////*/ app.use(express.static(path.resolve('public'))); app.use(express.static(path.resolve('src/views'))); app.use('/images/', express.static(path.resolve('public/images'))); // Test socket client app.get('/socketClient', function (req, res) { res.sendFile(path.join(process.cwd(), '/public/socketClient.html')); }); /*/////////////////////////////////////////////////////////////// ///// END STATIC PATH ///// ///////////////////////////////////////////////////////////////*/ // Catch 404 and forward to error handler app.use(function (req, res, next) { // Normalize error format let error = HttpResponse.returnErrorWithMessage(`Not found: ${req.method} ${req.originalUrl}`); // Set error status code res.status(404); // Pass to the next middleware next(error); }); // Step 1: Write error logs file in production mode if (process.env.NODE_ENV === 'development') { app.use((err, req, res, next) => { next(err); }); } // Step 2: Return meaningful error, so there is no stack traces leaked to user app.use(function (err, req, res, next) { if (err instanceof CustomResponse && res.statusCode !== null) { res.json(err); } else { // Set error status code res.status(500); HttpResponse.returnInternalServerResponseWithMessage(res, err.message); } }); // Create http server with express const httpServer = http.createServer(app); // Start Express server httpServer.listen(process.env.PORT || 3000, () => { console.log(' App is running at http://localhost:%d in %s mode', process.env.PORT || 3000, app.get('env')); console.log(' Press CTRL-C to stop\n'); }); // Allow maximum 20 mongo connection listener process.setMaxListeners(20); // Init agenda global.agendaInstance = new Agenda(); })();
作为MEAN技术栈新手,我是否遗漏了某些配置或步骤导致应用崩溃?恳请提供排查思路。
排查思路
1. 查看具体错误信息
Nodemon的提示只说明崩溃,没有细节。直接用Node运行项目:node server.js,控制台会输出完整错误栈,这是定位问题的核心步骤。
2. 检查依赖与版本兼容性
- 执行
npm install确认所有依赖已安装,无安装报错; - 部分包在Node v16下可能存在兼容问题:比如
body-parser已被Express 4.16+内置,单独安装的版本可能和当前Express冲突;swagger-jsdoc、agenda等包需确认是否支持Node v16,可查看package.json中的版本号,尝试升级或降级到兼容版本。
3. 验证.env文件配置
代码依赖dotenv加载环境变量,若文件缺失或关键配置错误会直接崩溃:
- 确认项目根目录存在
.env文件,包含必要配置:PORT=3000 NODE_ENV=development agenda.dbUri=mongodb://localhost:27017/your-db-name - 检查
initGlobalVariables()是否正确初始化global.configs,确保global.configs.agenda.dbUri能正常读取。
4. 确认文件/目录存在性与权限
代码中用到的路径需逐一验证:
src/views:确认目录存在,且有.hbs模板文件;public、public/images:确认目录存在;logs目录:代码会自动创建,但需确保当前用户有读写权限,可手动创建目录测试。
5. 给异步代码添加错误捕获
当前自执行async函数无错误捕获,一旦initGlobalVariables()、路由导入或Agenda初始化出错,会直接崩溃且无日志:
- 添加try-catch包裹核心代码:
(async () => { try { // 原代码内容 } catch (err) { console.error('应用初始化失败:', err); process.exit(1); } })();
6. 检查MongoDB连接状态
Agenda依赖MongoDB,若服务未启动或连接字符串错误会导致崩溃:
- 确认MongoDB服务正在运行;
- 用MongoDB Compass或命令行测试
agenda.dbUri的连接是否正常。
7. 验证路由模块正确性
import('./routes')导入的模块需正确导出接收app参数的函数:
- 检查
routes/index.js(或routes.ts)的导出逻辑; - 单独运行路由模块代码,确认无语法或逻辑错误。
8. 清理缓存与重启环境
- 清理Node缓存:
npm cache clean --force,重新安装依赖; - 重启终端和IDE,避免残留进程占用资源;
- 检查端口占用:用
netstat -ano | findstr :3000(Windows)确认端口未被其他程序占用。
内容的提问来源于stack exchange,提问作者lands homes
相关产品推荐
相关产品推荐

