阿里云主机折上折
  • 微信号
Current Site:Index > Project structure and directory organization standards

Project structure and directory organization standards

Author:Chuan Chen 阅读数:35551人阅读 分类: Node.js

Project Structure and Directory Organization Standards

The structure and directory organization of an Express project are crucial for code maintainability and scalability. A well-organized directory structure helps team members quickly understand the project architecture, reduces communication overhead, and facilitates future feature expansion and maintenance.

Basic Directory Structure

A typical basic directory structure for an Express project is as follows:

project-root/
├── node_modules/
├── src/
│   ├── controllers/
│   ├── models/
│   ├── routes/
│   ├── middlewares/
│   ├── services/
│   ├── utils/
│   ├── config/
│   ├── public/
│   ├── views/
│   └── app.js
├── tests/
├── .env
├── .gitignore
├── package.json
└── README.md

Core Directory Details

controllers Directory

Stores the business logic processing layer, responsible for receiving request parameters, invoking service layers to handle business logic, and returning responses:

// src/controllers/userController.js
const userService = require('../services/userService');

exports.getUser = async (req, res) => {
  try {
    const user = await userService.getUserById(req.params.id);
    res.json(user);
  } catch (error) {
    res.status(500).json({ error: error.message });
  }
};

models Directory

Defines data models and database interaction logic, often used with ORMs like Sequelize or Mongoose:

// src/models/userModel.js
const mongoose = require('mongoose');

const userSchema = new mongoose.Schema({
  username: { type: String, required: true },
  email: { type: String, required: true, unique: true },
  password: { type: String, required: true }
}, { timestamps: true });

module.exports = mongoose.model('User', userSchema);

routes Directory

Defines API routes and directs requests to the corresponding controllers:

// src/routes/userRoutes.js
const express = require('express');
const router = express.Router();
const userController = require('../controllers/userController');

router.get('/:id', userController.getUser);
router.post('/', userController.createUser);
router.put('/:id', userController.updateUser);

module.exports = router;

Advanced Directory Organization

Feature-Based Modularization

For large projects, a feature-based modular approach can be adopted:

src/
├── modules/
│   ├── auth/
│   │   ├── auth.controller.js
│   │   ├── auth.model.js
│   │   ├── auth.routes.js
│   │   └── auth.service.js
│   ├── user/
│   │   ├── user.controller.js
│   │   ├── user.model.js
│   │   ├── user.routes.js
│   │   └── user.service.js
│   └── product/
│       ├── product.controller.js
│       ├── product.model.js
│       ├── product.routes.js
│       └── product.service.js
├── core/
│   ├── database.js
│   ├── server.js
│   └── middleware.js
└── app.js

Configuration Management

Centralize configuration management with support for different environments:

// src/config/index.js
require('dotenv').config();

module.exports = {
  app: {
    port: process.env.PORT || 3000,
    env: process.env.NODE_ENV || 'development'
  },
  db: {
    uri: process.env.MONGODB_URI,
    options: {
      useNewUrlParser: true,
      useUnifiedTopology: true
    }
  },
  jwt: {
    secret: process.env.JWT_SECRET,
    expiresIn: '24h'
  }
};

Middleware Organization

Middleware should be organized separately for reusability and management:

// src/middlewares/authMiddleware.js
const jwt = require('jsonwebtoken');
const config = require('../config');

module.exports = (req, res, next) => {
  const token = req.header('Authorization')?.replace('Bearer ', '');
  
  if (!token) {
    return res.status(401).json({ error: 'Access denied' });
  }

  try {
    const decoded = jwt.verify(token, config.jwt.secret);
    req.user = decoded;
    next();
  } catch (error) {
    res.status(400).json({ error: 'Invalid token' });
  }
};

Utility Organization

Centralize common utility functions:

// src/utils/response.js
exports.success = (res, data, status = 200) => {
  res.status(status).json({
    success: true,
    data
  });
};

exports.error = (res, message, status = 400) => {
  res.status(status).json({
    success: false,
    error: message
  });
};

Application Entry File

The main application file should remain concise, primarily handling initialization:

// src/app.js
const express = require('express');
const cors = require('cors');
const helmet = require('helmet');
const morgan = require('morgan');
const config = require('./config');
const routes = require('./routes');

const app = express();

// Middleware
app.use(cors());
app.use(helmet());
app.use(morgan('dev'));
app.use(express.json());
app.use(express.urlencoded({ extended: true }));

// Routes
app.use('/api', routes);

// Error handling
app.use((err, req, res, next) => {
  console.error(err.stack);
  res.status(500).json({ error: 'Internal Server Error' });
});

module.exports = app;

Test Directory Structure

The test directory should mirror the source code structure:

tests/
├── unit/
│   ├── controllers/
│   ├── models/
│   └── services/
├── integration/
│   ├── routes/
│   └── middlewares/
└── e2e/
    ├── api/
    └── auth/

Static Resource Management

Static resources should be organized under the public directory:

public/
├── images/
├── css/
├── js/
└── uploads/

View Template Organization

If using a template engine, organize view files logically:

views/
├── layouts/
│   └── main.hbs
├── partials/
│   ├── header.hbs
│   └── footer.hbs
├── home/
│   └── index.hbs
└── user/
    ├── profile.hbs
    └── edit.hbs

Environment Variable Management

Use .env files to manage environment variables and load them via dotenv:

# .env
PORT=3000
NODE_ENV=development
MONGODB_URI=mongodb://localhost:27017/myapp
JWT_SECRET=mysecretkey

Package Management Standards

Organize scripts and dependencies properly in package.json:

{
  "scripts": {
    "start": "node src/app.js",
    "dev": "nodemon src/app.js",
    "test": "jest",
    "lint": "eslint .",
    "format": "prettier --write ."
  },
  "dependencies": {
    "express": "^4.18.2",
    "mongoose": "^7.0.3"
  },
  "devDependencies": {
    "nodemon": "^2.0.22",
    "eslint": "^8.36.0",
    "prettier": "^2.8.7"
  }
}

Documentation and Instructions

The project root should include necessary documentation files:

  • README.md: Project overview, installation instructions, usage guide
  • CHANGELOG.md: Version change log
  • API_DOC.md: API documentation
  • .editorconfig: Unified editor configuration
  • .eslintrc: Code style check configuration
  • .prettierrc: Code formatting configuration

Large-Scale Project Extended Structure

For enterprise-level applications, consider a more complex structure:

src/
├── api/
│   ├── v1/
│   │   ├── modules/
│   │   └── routes.js
│   └── v2/
│       ├── modules/
│       └── routes.js
├── core/
│   ├── exceptions/
│   ├── logging/
│   ├── database/
│   └── utils/
├── jobs/
├── migrations/
├── seeders/
└── app.js

本站部分内容来自互联网,一切版权均归源网站或源作者所有。

如果侵犯了你的权益请来信告知我们删除。邮箱:cc@cccx.cn

Front End Chuan

Front End Chuan, Chen Chuan's Code Teahouse 🍵, specializing in exorcising all kinds of stubborn bugs 💻. Daily serving baldness-warning-level development insights 🛠️, with a bonus of one-liners that'll make you laugh for ten years 🐟. Occasionally drops pixel-perfect romance brewed in a coffee cup ☕.