您现在的位置是:网站首页 > 项目结构与目录组织规范文章详情

项目结构与目录组织规范

Express框架作为Node.js中最流行的Web应用框架之一,其项目结构与目录组织规范直接影响代码的可维护性和扩展性。合理的目录划分和模块化设计能够提升团队协作效率,降低后期维护成本。

核心目录结构

典型的Express项目通常包含以下核心目录:

project-root/
├── bin/                # 启动脚本
├── config/             # 配置文件
├── public/             # 静态资源
├── routes/             # 路由定义
├── models/             # 数据模型
├── controllers/        # 业务逻辑
├── middlewares/        # 自定义中间件
├── views/              # 模板文件
├── tests/              # 测试代码
├── app.js              # 应用入口
└── package.json        # 项目配置

入口文件设计

应用入口文件app.js应当保持简洁,主要完成以下工作:

const express = require('express');
const path = require('path');
const cookieParser = require('cookie-parser');
const logger = require('morgan');

// 路由引入
const indexRouter = require('./routes/index');
const apiRouter = require('./routes/api');

const app = express();

// 中间件配置
app.use(logger('dev'));
app.use(express.json());
app.use(express.urlencoded({ extended: false }));
app.use(cookieParser());
app.use(express.static(path.join(__dirname, 'public')));

// 路由挂载
app.use('/', indexRouter);
app.use('/api', apiRouter);

// 错误处理中间件
app.use((err, req, res, next) => {
  res.status(err.status || 500);
  res.json({ error: err.message });
});

module.exports = app;

路由组织规范

路由文件应当按功能模块拆分,避免将所有路由定义集中在单个文件中:

// routes/api/users.js
const express = require('express');
const router = express.Router();
const usersController = require('../controllers/users');

router.get('/', usersController.list);
router.post('/', usersController.create);
router.get('/:id', usersController.show);
router.put('/:id', usersController.update);
router.delete('/:id', usersController.delete);

module.exports = router;

然后在主路由文件中进行聚合:

// routes/index.js
const express = require('express');
const router = express.Router();

router.use('/api/users', require('./api/users'));
router.use('/api/products', require('./api/products'));

module.exports = router;

控制器设计原则

控制器应当保持精简,主要处理HTTP请求和响应:

// controllers/users.js
const User = require('../models/user');

exports.list = async (req, res, next) => {
  try {
    const users = await User.find();
    res.json(users);
  } catch (err) {
    next(err);
  }
};

exports.create = async (req, res, next) => {
  try {
    const user = new User(req.body);
    await user.save();
    res.status(201).json(user);
  } catch (err) {
    next(err);
  }
};

中间件管理

自定义中间件应当集中存放在middlewares目录中:

// middlewares/auth.js
const jwt = require('jsonwebtoken');

module.exports = (req, res, next) => {
  const token = req.header('Authorization');
  if (!token) return res.status(401).send('Access denied');
  
  try {
    const verified = jwt.verify(token, process.env.JWT_SECRET);
    req.user = verified;
    next();
  } catch (err) {
    res.status(400).send('Invalid token');
  }
};

环境配置管理

配置文件应当按环境区分,并通过环境变量加载:

// config/default.js
module.exports = {
  port: process.env.PORT || 3000,
  db: {
    uri: process.env.DB_URI || 'mongodb://localhost:27017/dev_db'
  },
  jwt: {
    secret: process.env.JWT_SECRET || 'default_secret'
  }
};
// config/production.js
module.exports = {
  db: {
    uri: process.env.DB_URI
  },
  jwt: {
    secret: process.env.JWT_SECRET
  }
};

静态资源管理

静态资源应当分类存放:

public/
├── images/       # 图片资源
├── js/           # 客户端JavaScript
├── css/          # 样式表
└── uploads/      # 用户上传文件

测试目录结构

测试文件应当与被测模块保持相同结构:

tests/
├── unit/         # 单元测试
│   ├── controllers/
│   ├── models/
│   └── middlewares/
└── integration/  # 集成测试
    ├── api/
    └── routes/

视图模板组织

使用模板引擎时,视图文件应当模块化:

views/
├── layouts/      # 布局文件
│   └── main.hbs
├── partials/     # 公共组件
│   ├── header.hbs
│   └── footer.hbs
└── pages/        # 具体页面
    ├── home.hbs
    └── users/
        ├── list.hbs
        └── detail.hbs

模块化实践

大型项目可以考虑功能模块划分:

modules/
├── user/         # 用户模块
│   ├── controllers/
│   ├── models/
│   ├── routes/
│   └── tests/
└── product/      # 产品模块
    ├── controllers/
    ├── models/
    ├── routes/
    └── tests/

日志管理

日志文件应当按类型和日期组织:

logs/
├── access/       # 访问日志
│   ├── 2023-08-01.log
│   └── 2023-08-02.log
└── error/        # 错误日志
    ├── 2023-08-01.log
    └── 2023-08-02.log

文档规范

项目文档应当统一存放:

docs/
├── api.md        # API文档
├── db.md         # 数据库设计
└── setup.md      # 环境搭建

工具脚本管理

自定义脚本应当分类存放:

scripts/
├── db/           # 数据库脚本
│   ├── migrate.js
│   └── seed.js
└── deploy/       # 部署脚本
    ├── staging.sh
    └── production.sh

环境变量管理

敏感配置应当通过.env文件管理:

# .env.example
DB_URI=mongodb://localhost:27017/dev_db
JWT_SECRET=your_jwt_secret
PORT=3000

代码风格统一

项目应当包含统一的代码风格配置:

// .eslintrc.json
{
  "extends": "airbnb-base",
  "rules": {
    "linebreak-style": ["error", "unix"],
    "indent": ["error", 2],
    "quotes": ["error", "single"]
  }
}

构建产物管理

前端构建产物应当统一输出:

dist/             # 构建输出目录
├── assets/       # 编译后的静态资源
│   ├── js/
│   ├── css/
│   └── images/
└── index.html    # 生成的HTML文件

异常处理规范

全局异常应当统一处理:

// middlewares/errorHandler.js
module.exports = (err, req, res, next) => {
  console.error(err.stack);
  
  if (err instanceof CustomError) {
    return res.status(err.statusCode).json({
      error: err.message,
      details: err.details
    });
  }

  res.status(500).json({
    error: 'Internal Server Error'
  });
};

数据库迁移管理

数据库变更应当通过迁移脚本管理:

// scripts/db/migrate/20230801-create-users.js
exports.up = async (db) => {
  await db.createCollection('users', {
    validator: {
      $jsonSchema: {
        bsonType: "object",
        required: ["username", "email"],
        properties: {
          username: { bsonType: "string" },
          email: { bsonType: "string" }
        }
      }
    }
  });
};

exports.down = async (db) => {
  await db.collection('users').drop();
};

依赖管理规范

第三方依赖应当分类管理:

// package.json
{
  "dependencies": {
    "express": "^4.18.2",
    "mongoose": "^7.3.1"
  },
  "devDependencies": {
    "eslint": "^8.45.0",
    "jest": "^29.6.1"
  }
}

自动化任务配置

常用任务应当通过npm scripts定义:

// package.json
{
  "scripts": {
    "start": "node bin/www",
    "dev": "nodemon bin/www",
    "test": "jest",
    "lint": "eslint .",
    "migrate": "node scripts/db/migrate.js"
  }
}

我的名片

网名:~川~

岗位:console.log 调试员

坐标:重庆市-九龙坡区

邮箱:cc@qdcc.cn

沙漏人生

站点信息

  • 建站时间:2013/03/16
  • 本站运行
  • 文章数量
  • 总访问量
微信公众号
每次关注
都是向财富自由迈进的一步