A Comprehensive Overview of a Node.js TypeScript Project with DevOps: Structure, Code, and Configuration
Explore the essential components of building a robust Node.js TypeScript project integrated with DevOps practices. This guide provides a detailed breakdown of the project structure, complete with code snippets and configurations for each file and directory, empowering you to streamline development, testing, and deployment processes effectively. Whether you're a beginner or an experienced developer, this comprehensive overview will enhance your understanding of creating scalable applications in a modern development environment.
Project Structure
π node-typescript-project-with-devops/ βββ π node_modules # Node.js modules βββ π .gitignore # Specifies files and directories to be ignored by Git βββ π .dockerignore # Specifies files and directories to be ignored by Docker βββ π .env # Environment variables file βββ π example.env # Example environment variables file βββ π uploads # Folder for uploaded files β βββ ... βββ π src β βββ π server.ts # Main entry point for the application β βββ π bin # Contains binaries or executable files β β βββ π www # Start script for the server β βββ π config # Configuration files β β βββ π redis.config # Redis configuration β β βββ π mongo.config # MongoDB configuration β β βββ π postgres.config # PostgreSQL configuration β β βββ π nginx.conf # Nginx configuration file β βββ π controllers # Controller files β β βββ π customer.ts # Customer-related controller β β βββ π product.ts # Product-related controller β β βββ ... β βββ π middleware # Middleware files β β βββ π auth.ts # Authentication middleware β β βββ π logger.ts # Logger middleware β β βββ ... β βββ π models # Model files β β βββ π customer.ts # Customer model β β βββ π product.ts # Product model β β βββ ... β βββ π routes # Route files β β βββ π api.ts # API routes β β βββ π auth.ts # Authentication routes β β βββ ... β βββ π tests # Test files β β βββ π unit # Unit tests β β βββ π integration # Integration tests β β βββ π e2e # End-to-end tests β β βββ ... β βββ π utils # Utility files β βββ π validation.ts # Validation utilities β βββ π helpers.ts # Helper functions β βββ ... βββ π Dockerfile # Dockerfile for building the Node.js app image βββ π docker-compose.yml # Docker Compose configuration βββ π nodemon.json # Nodemon configuration for development βββ π package.json # Project dependencies and scripts βββ π ansible # Ansible directory β βββ π deploy.yml # Ansible playbook for deployment β βββ π roles # Ansible roles (if any) β βββ ... βββ π helm # Helm chart directory βββ π your-helm-chart/ β βββ π charts # Charts for dependencies β βββ π templates # Template files for Kubernetes resources β β βββ π deployment.yaml # Deployment configuration for Node.js app β β βββ π service.yaml # Service configuration for exposing the Node.js app β β βββ π ingress.yaml # Ingress configuration for Nginx β β βββ π configmap.yaml # ConfigMap for environment variables β βββ π Chart.yaml # Metadata for your Helm chart β βββ π values.yaml # Default values for your templates βββ π jenkins # Jenkins directory for pipeline configuration β βββ π Jenkinsfile # Declarative pipeline for Jenkins β βββ π jenkins-config.groovy # Configuration script for Jenkins setup β βββ π jobs # Jenkins job configuration files β βββ π build-node-app.xml # Jenkins job for building Node.js app β βββ π deploy-node-app.xml # Jenkins job for deploying Node.js app
Detailed File and Code Examples
1. .gitignore
node_modules/ dist/ .env npm-debug.log .DS_Store uploads/
2. .dockerignore
node_modules npm-debug.log .git .gitignore Dockerfile docker-compose.yml
3. .env
NODE_ENV=production PORT=3000 MONGO_URI=mongodb://localhost:27017/mydatabase REDIS_URL=redis://localhost:6379 POSTGRES_URI=postgresql://user:password@localhost:5432/mydatabase JWT_SECRET=mysecret
4. example.env
NODE_ENV=development PORT=3000 MONGO_URI=mongodb://localhost:27017/mydatabase REDIS_URL=redis://localhost:6379 POSTGRES_URI=postgresql://user:password@localhost:5432/mydatabase JWT_SECRET=mysecret
5. src/server.ts
import express from 'express'; import mongoose from 'mongoose'; import { json } from 'body-parser'; import { routes } from './routes/api'; import { connectRedis } from './config/redis.config'; import { connectMongo } from './config/mongo.config'; const app = express(); const PORT = process.env.PORT || 3000; app.use(json()); app.use('/api', routes); // MongoDB and Redis connection connectMongo(); connectRedis(); app.listen(PORT, () => { console.log(`Server is running on port ${PORT}`); });
6. src/bin/www
#!/usr/bin/env node import app from '../server'; const PORT = process.env.PORT || 3000; app.listen(PORT, () => { console.log(`Server started on port ${PORT}`); });
7. src/config/redis.config
import Redis from 'ioredis'; const redis = new Redis(process.env.REDIS_URL); export const connectRedis = () => { redis.on('connect', () => { console.log('Connected to Redis'); }); redis.on('error', (err) => { console.error('Redis error:', err); }); };
8. src/config/mongo.config
import mongoose from 'mongoose'; export const connectMongo = async () => { try { await mongoose.connect(process.env.MONGO_URI); console.log('Connected to MongoDB'); } catch (error) { console.error('MongoDB connection error:', error); } };
9. src/config/postgres.config
// PostgreSQL configuration // You can set up Sequelize or pg-promise here
10. src/config/nginx.conf
server { listen 80; location / { proxy_pass http://localhost:3000; # Adjust according to your Node.js server proxy_http_version 1.1; proxy_set_header Upgrade $http_upgrade; proxy_set_header Connection 'upgrade'; proxy_set_header Host $host; proxy_cache_bypass $http_upgrade; } }
11. src/controllers/customer.ts
import { Request, Response } from 'express'; export const getCustomers = (req: Request, res: Response) => { // Logic to get customers }; export const createCustomer = (req: Request, res: Response) => { // Logic to create a customer };
12. src/controllers/product.ts
import { Request, Response } from 'express'; export const getProducts = (req: Request, res: Response) => { // Logic to get products }; export const createProduct = (req: Request, res: Response) => { // Logic to create a product };
13. src/middleware/auth.ts
import { Request, Response, NextFunction } from 'express'; export const authMiddleware = (req: Request, res: Response, next: NextFunction) => { // Authentication logic next(); };
14. src/middleware/logger.ts
import { Request, Response, NextFunction } from 'express'; export const loggerMiddleware = (req: Request, res: Response, next: NextFunction) => { console.log(`${req.method} ${req.url}`); next(); };
15. src/models/customer.ts
import mongoose, { Schema, Document } from 'mongoose'; export interface ICustomer extends Document { name: string; email: string; } const CustomerSchema: Schema = new Schema({ name: { type: String, required: true }, email: { type: String, required: true }, }); export const Customer = mongoose .model<ICustomer>('Customer', CustomerSchema);
16. src/models/product.ts
import mongoose, { Schema, Document } from 'mongoose'; export interface IProduct extends Document { title: string; price: number; } const ProductSchema: Schema = new Schema({ title: { type: String, required: true }, price: { type: Number, required: true }, }); export const Product = mongoose.model<IProduct>('Product', ProductSchema);
17. src/routes/api.ts
import { Router } from 'express'; import { getCustomers, createCustomer } from '../controllers/customer'; import { getProducts, createProduct } from '../controllers/product'; const router = Router(); router.get('/customers', getCustomers); router.post('/customers', createCustomer); router.get('/products', getProducts); router.post('/products', createProduct); export const routes = router;
18. src/tests/unit/customer.test.ts
import { getCustomers } from '../../controllers/customer'; import { Request, Response } from 'express'; describe('Customer Controller', () => { it('should get customers', () => { const req = {} as Request; const res = { send: jest.fn(), } as unknown as Response; getCustomers(req, res); expect(res.send).toHaveBeenCalled(); }); });
19. Dockerfile
# Use an official Node.js runtime as a parent image FROM node:14 # Set the working directory WORKDIR /usr/src/app # Copy package.json and package-lock.json COPY package*.json ./ # Install dependencies RUN npm install # Copy the rest of the application code COPY . . # Expose the application port EXPOSE 3000 # Command to run the application CMD [ "npm", "start" ]
20. docker-compose.yml
version: '3.8' services: node-app: build: . ports: - '3000:3000' environment: NODE_ENV: development MONGO_URI: mongodb://mongo:27017/mydatabase REDIS_URL: redis://redis:6379 POSTGRES_URI: postgresql://user:password@postgres:5432/mydatabase depends_on: - mongo - redis - postgres mongo: image: mongo restart: always ports: - '27017:27017' redis: image: redis restart: always ports: - '6379:6379' postgres: image: postgres restart: always environment: POSTGRES_USER: user POSTGRES_PASSWORD: password POSTGRES_DB: mydatabase ports: - '5432:5432'
21. nodemon.json
{ "watch": ["src"], "ext": "ts", "exec": "ts-node src/server.ts" }
22. package.json
{ "name": "node-typescript-project-with-devops", "version": "1.0.0", "scripts": { "start": "ts-node src/server.ts", "dev": "nodemon", "test": "jest" }, "dependencies": { "express": "^4.17.1", "mongoose": "^5.10.9", "ioredis": "^4.17.3", "dotenv": "^8.2.0", "pg": "^8.5.1" }, "devDependencies": { "@types/express": "^4.17.11", "@types/jest": "^26.0.0", "jest": "^26.6.0", "ts-jest": "^26.4.0", "typescript": "^4.0.3", "nodemon": "^2.0.4", "ts-node": "^9.1.1" } }
23. ansible/deploy.yml
--- - hosts: all tasks: - name: Ensure Node.js is installed apt: name: nodejs state: present - name: Copy application files copy: src: /path/to/your/local/project/ dest: /path/to/remote/server/ - name: Install dependencies command: npm install args: chdir: /path/to/remote/server/
24. helm/your-helm-chart/templates/deployment.yaml
apiVersion: apps/v1 kind: Deployment metadata: name: node-app spec: replicas: 2 selector: matchLabels: app: node-app template: metadata: labels: app: node-app spec: containers: - name: node-app image: your-node-app-image ports: - containerPort: 3000 env: - name: NODE_ENV value: "production" - name: MONGO_URI value: "mongodb://mongo:27017/mydatabase" - name: REDIS_URL value: "redis://redis:6379" - name: POSTGRES_URI value: "postgresql://user:password@postgres:5432/mydatabase"
25. helm/your-helm-chart/templates/service.yaml
apiVersion: v1 kind: Service metadata: name: node-app spec: type: LoadBalancer ports: - port: 80 targetPort: 3000 selector: app: node-app
26. jenkins/Jenkinsfile
pipeline { agent any stages { stage('Build') { steps { script { docker.build("your-node-app-image") } } } stage('Deploy') { steps { script { sh 'docker-compose up -d' } } } } }
27. jenkins/jenkins-config.groovy
// Jenkins configuration script for initial setup
Additional Configuration and Usage
-
Run the Application:
- Use
npm start
ornpm run dev
to start the application in development mode with Nodemon.
- Use
-
Docker:
- Build the Docker image with
docker build -t your-node-app-image .
- Run
docker-compose up
to start all services defined indocker-compose.yml
.
- Build the Docker image with
-
Ansible:
- Execute the Ansible playbook with
ansible-playbook deploy.yml
.
- Execute the Ansible playbook with
-
Helm:
- Package and deploy your Helm chart using
helm install your-helm-chart
.
- Package and deploy your Helm chart using
-
Jenkins:
- Set up your Jenkins server and create a pipeline using the
Jenkinsfile
provided.
- Set up your Jenkins server and create a pipeline using the
-
Testing:
- Run tests using
npm test
.
- Run tests using
This structure and configuration allow for a solid foundation for a Node.js TypeScript project with DevOps best practices, making it easier to develop, test, and deploy your application efficiently. If you have any specific requirements or changes, feel free to change this structure is't Bible :)
Happy coding...
Top comments (0)