Maison  >  Article  >  interface Web  >  De zéro à vitrine : mon parcours pour créer un site de commerce électronique

De zéro à vitrine : mon parcours pour créer un site de commerce électronique

Susan Sarandon
Susan Sarandonoriginal
2024-11-10 02:54:02193parcourir

Contenu

  1. Présentation
  2. Pile technologique
  3. Aperçu rapide
  4. API
  5. Frontend
  6. Tableau de bord d'administration
  7. Ressources

Code source : https://github.com/aelassas/wexcommerce

Démo : https://wexcommerce.dynv6.net:8002

Introduction

Pour les développeurs qui apprécient la liberté de création et le contrôle technique, les plateformes de commerce électronique traditionnelles comme Shopify peuvent sembler restrictives. Bien que les modèles de Shopify offrent une configuration rapide et que leur API Storefront offre une certaine flexibilité, aucune des deux solutions n'offre la liberté architecturale complète dont les développeurs modernes recherchent.

L'idée est née d'un désir de construire sans frontières – un site de commerce électronique entièrement personnalisable où chaque aspect est sous votre contrôle :

  • Possédez l'UI/UX : Concevez des expériences client uniques sans lutter contre les limitations des modèles
  • Contrôlez le backend : implémentez une logique métier personnalisée et des structures de données qui correspondent parfaitement aux exigences
  • Maîtrisez DevOps : Déployez, faites évoluer et surveillez l'application avec les outils et flux de travail préférés
  • Extendez librement : ajoutez de nouvelles fonctionnalités et intégrations sans contraintes de plate-forme ni frais supplémentaires

Pile technologique

Voici la pile technologique qui a rendu cela possible :

  • Node.js
  • Suivant.js
  • MongoDB
  • MUI
  • TypeScript
  • Rayure
  • Docker

Une décision clé en matière de conception a été prise d'utiliser TypeScript en raison de ses nombreux avantages. TypeScript offre un typage, des outils et une intégration puissants, ce qui donne lieu à un code de haute qualité, évolutif, plus lisible et maintenable, facile à déboguer et à tester.

J'ai choisi Next.js pour ses puissantes capacités de rendu, MongoDB pour une modélisation flexible des données et Stripe pour le traitement sécurisé des paiements.

En choisissant cette pile, vous ne construisez pas seulement un magasin : vous investissez dans une fondation qui peut évoluer avec vos besoins, soutenue par des technologies open source robustes et une communauté de développeurs croissante.

Construire un site avec Next.js fournit une base solide pour développer une entreprise. Concentrez-vous sur les performances, la sécurité et l'expérience utilisateur tout en maintenant la qualité du code et la documentation. Des mises à jour et une surveillance régulières garantiront que la plateforme reste compétitive et fiable.

Next.js se démarque comme un excellent choix grâce à :

  • Performances supérieures : optimisations intégrées pour des chargements de pages rapides et des expériences utilisateur fluides
  • Avantages SEO : capacités de rendu côté serveur qui garantissent que vos produits sont détectables
  • Évolutivité : une architecture prête pour l'entreprise qui évolue avec votre entreprise
  • Rich Ecosystem : Vaste collection de bibliothèques et d'outils pour un développement rapide
  • Expérience développeur : workflow de développement intuitif avec rechargement à chaud et routage automatique

Aperçu rapide

L'extrémité avant

Depuis le frontend, l'utilisateur peut rechercher des produits disponibles, ajouter des produits au panier et finaliser le paiement.

Ci-dessous la page de destination du frontend :

From Zero to Storefront: My Journey Building an E-commerce Site

Ci-dessous la page de recherche du frontend :

From Zero to Storefront: My Journey Building an E-commerce Site

Vous trouverez ci-dessous un exemple de page de produit :

From Zero to Storefront: My Journey Building an E-commerce Site

Vous trouverez ci-dessous une vue plein écran des images du produit :

From Zero to Storefront: My Journey Building an E-commerce Site

Ci-dessous la page du panier :

From Zero to Storefront: My Journey Building an E-commerce Site

Ci-dessous la page de paiement :

From Zero to Storefront: My Journey Building an E-commerce Site

Vous trouverez ci-dessous la page de connexion :

From Zero to Storefront: My Journey Building an E-commerce Site

Ci-dessous la page d'inscription :

From Zero to Storefront: My Journey Building an E-commerce Site

Ci-dessous la page où l'utilisateur peut consulter ses commandes :

From Zero to Storefront: My Journey Building an E-commerce Site

C'est ça ! Ce sont les pages principales du frontend.

Tableau de bord d'administration

À partir du tableau de bord d'administration, les administrateurs peuvent gérer les catégories, les produits, les utilisateurs et les commandes.

Les administrateurs peuvent également gérer les paramètres suivants :

  • Paramètres locaux : Langue de la plateforme (anglais ou français) et devise
  • Paramètres de livraison : modes de livraison activés et coût de chacun
  • Paramètres de paiement : modes de paiement activés (carte de crédit, paiement à la livraison ou virement bancaire)
  • Paramètres bancaires : informations bancaires pour le virement bancaire (IBAN et autres informations)

Vous trouverez ci-dessous la page de connexion :

From Zero to Storefront: My Journey Building an E-commerce Site

Vous trouverez ci-dessous la page du tableau de bord à partir de laquelle les administrateurs peuvent voir et gérer les commandes :

From Zero to Storefront: My Journey Building an E-commerce Site

Vous trouverez ci-dessous la page à partir de laquelle les administrateurs gèrent les catégories :

From Zero to Storefront: My Journey Building an E-commerce Site

Vous trouverez ci-dessous la page à partir de laquelle les administrateurs peuvent voir et gérer les produits :

From Zero to Storefront: My Journey Building an E-commerce Site

Vous trouverez ci-dessous la page à partir de laquelle les administrateurs modifient les produits :

From Zero to Storefront: My Journey Building an E-commerce Site

Vous trouverez ci-dessous une vue plein écran des images du produit :

From Zero to Storefront: My Journey Building an E-commerce Site

Vous trouverez ci-dessous la page des paramètres :

From Zero to Storefront: My Journey Building an E-commerce Site

C'est tout. Ce sont les pages principales du tableau de bord d'administration.

API

From Zero to Storefront: My Journey Building an E-commerce Site

L'API est une application serveur Node.js qui expose une API RESTful utilisant Express qui donne accès à la base de données MongoDB.

L'API est utilisée par le frontend, le tableau de bord d'administration et sera également utilisée par l'application mobile.

L'API expose toutes les fonctions nécessaires au tableau de bord d'administration et au frontend. L'API suit le modèle de conception MVC. JWT est utilisé pour l'authentification. Certaines fonctions nécessitent une authentification comme les fonctions liées à la gestion des produits et des commandes, et d'autres ne nécessitent pas d'authentification comme la récupération des catégories et des produits disponibles pour les utilisateurs non authentifiés :

  • Le dossier ./api/src/models/ contient des modèles MongoDB.
  • Le dossier ./api/src/routes/ contient les routes Express.
  • Le dossier ./api/src/controllers/ contient des contrôleurs.
  • Le dossier ./api/src/middlewares/ contient des middlewares.
  • ./api/src/app.ts est le serveur principal sur lequel les routes sont chargées.
  • ./api/src/index.ts est le point d'entrée principal de l'API.

index.ts est sur le serveur principal :

import 'dotenv/config'
import process from 'node:process'
import fs from 'node:fs/promises'
import http from 'node:http'
import https, { ServerOptions } from 'node:https'
import * as env from './config/env.config'
import * as databaseHelper from './common/databaseHelper'
import app from './app'
import * as logger from './common/logger'

if (
  await databaseHelper.connect(env.DB_URI, env.DB_SSL, env.DB_DEBUG)
  && await databaseHelper.initialize()
) {
  let server: http.Server | https.Server

  if (env.HTTPS) {
    https.globalAgent.maxSockets = Number.POSITIVE_INFINITY
    const privateKey = await fs.readFile(env.PRIVATE_KEY, 'utf8')
    const certificate = await fs.readFile(env.CERTIFICATE, 'utf8')
    const credentials: ServerOptions = { key: privateKey, cert: certificate }
    server = https.createServer(credentials, app)

    server.listen(env.PORT, () => {
      logger.info('HTTPS server is running on Port', env.PORT)
    })
  } else {
    server = app.listen(env.PORT, () => {
      logger.info('HTTP server is running on Port', env.PORT)
    })
  }

  const close = () => {
    logger.info('Gracefully stopping...')
    server.close(async () => {
      logger.info(`HTTP${env.HTTPS ? 'S' : ''} server closed`)
      await databaseHelper.close(true)
      logger.info('MongoDB connection closed')
      process.exit(0)
    })
  }

  ['SIGINT', 'SIGTERM', 'SIGQUIT'].forEach((signal) => process.on(signal, close))
}

Il s'agit d'un fichier TypeScript qui démarre un serveur à l'aide de Node.js et Express. Il importe plusieurs modules, notamment dotenv, process, fs, http, https, mongoose et app. Il établit ensuite une connexion avec la base de données MongoDB. Il vérifie ensuite si la variable d'environnement HTTPS est définie sur true et, si tel est le cas, crée un serveur HTTPS à l'aide du module https ainsi que de la clé privée et du certificat fournis. Sinon, il crée un serveur HTTP à l'aide du module http. Le serveur écoute sur le port spécifié dans la variable d'environnement PORT.

La fonction close est définie pour arrêter gracieusement le serveur lorsqu'un signal de terminaison est reçu. Il ferme le serveur et la connexion MongoDB, puis quitte le processus avec un code d'état de 0. Enfin, il enregistre la fonction de fermeture à appeler lorsque le processus reçoit un signal SIGINT, SIGTERM ou SIGQUIT.

app.ts est le point d'entrée principal de l'API :

import express from 'express'
import compression from 'compression'
import helmet from 'helmet'
import nocache from 'nocache'
import cookieParser from 'cookie-parser'
import i18n from './lang/i18n'
import * as env from './config/env.config'
import cors from './middlewares/cors'
import allowedMethods from './middlewares/allowedMethods'
import userRoutes from './routes/userRoutes'
import categoryRoutes from './routes/categoryRoutes'
import productRoutes from './routes/productRoutes'
import cartRoutes from './routes/cartRoutes'
import orderRoutes from './routes/orderRoutes'
import notificationRoutes from './routes/notificationRoutes'
import deliveryTypeRoutes from './routes/deliveryTypeRoutes'
import paymentTypeRoutes from './routes/paymentTypeRoutes'
import settingRoutes from './routes/settingRoutes'
import stripeRoutes from './routes/stripeRoutes'
import wishlistRoutes from './routes/wishlistRoutes'
import * as helper from './common/helper'

const app = express()

app.use(helmet.contentSecurityPolicy())
app.use(helmet.dnsPrefetchControl())
app.use(helmet.crossOriginEmbedderPolicy())
app.use(helmet.frameguard())
app.use(helmet.hidePoweredBy())
app.use(helmet.hsts())
app.use(helmet.ieNoOpen())
app.use(helmet.noSniff())
app.use(helmet.permittedCrossDomainPolicies())
app.use(helmet.referrerPolicy())
app.use(helmet.xssFilter())
app.use(helmet.originAgentCluster())
app.use(helmet.crossOriginResourcePolicy({ policy: 'cross-origin' }))
app.use(helmet.crossOriginOpenerPolicy())

app.use(nocache())
app.use(compression({ threshold: 0 }))
app.use(express.urlencoded({ limit: '50mb', extended: true }))
app.use(express.json({ limit: '50mb' }))

app.use(cors())
app.options('*', cors())
app.use(cookieParser(env.COOKIE_SECRET))
app.use(allowedMethods)

app.use('/', userRoutes)
app.use('/', categoryRoutes)
app.use('/', productRoutes)
app.use('/', cartRoutes)
app.use('/', orderRoutes)
app.use('/', notificationRoutes)
app.use('/', deliveryTypeRoutes)
app.use('/', paymentTypeRoutes)
app.use('/', settingRoutes)
app.use('/', stripeRoutes)
app.use('/', wishlistRoutes)

i18n.locale = env.DEFAULT_LANGUAGE

await helper.mkdir(env.CDN_USERS)
await helper.mkdir(env.CDN_TEMP_USERS)
await helper.mkdir(env.CDN_CATEGORIES)
await helper.mkdir(env.CDN_TEMP_CATEGORIES)
await helper.mkdir(env.CDN_PRODUCTS)
await helper.mkdir(env.CDN_TEMP_PRODUCTS)

export default app

Tout d'abord, nous créons une application Express et chargeons des middlewares tels que cors, compression, casque et nocache. Nous avons mis en place diverses mesures de sécurité à l'aide de la bibliothèque middleware du casque. Nous importons également divers fichiers de route pour différentes parties de l'application telles que productRoutes, orderRoutes, CategoryRoutes, notificationRoutes, userRoutes. Enfin, nous chargeons les itinéraires Express et exportons l'application.

Il y a 11 routes dans l'API. Chaque route possède son propre contrôleur suivant le modèle de conception MVC et les principes SOLID. Ci-dessous les principaux itinéraires :

  • userRoutes : fournit des fonctions REST liées aux utilisateurs
  • categoryRoutes : fournit des fonctions REST liées aux catégories
  • productRoutes : fournit des fonctions REST liées aux produits
  • cartRoutes : fournit des fonctions REST liées aux chariots
  • wishlistRoutes : fournit des fonctions REST liées aux listes de souhaits
  • deliveryTypeRoutes : fournit des fonctions REST liées aux méthodes de livraison
  • paymentTypeRoutes : Fournit des fonctions REST liées aux modes de paiement
  • orderRoutes : fournit des fonctions REST liées aux commandes
  • notificationRoutes : Fournit des fonctions REST liées aux notifications
  • settingRoutes : fournit des fonctions REST liées aux paramètres
  • stripeRoutes : fournit des fonctions REST liées à la passerelle de paiement Stripe

Nous n'allons pas expliquer chaque itinéraire un par un. Prenons par exemple la catégorieRoutes et voyons comment elle a été réalisée :

import 'dotenv/config'
import process from 'node:process'
import fs from 'node:fs/promises'
import http from 'node:http'
import https, { ServerOptions } from 'node:https'
import * as env from './config/env.config'
import * as databaseHelper from './common/databaseHelper'
import app from './app'
import * as logger from './common/logger'

if (
  await databaseHelper.connect(env.DB_URI, env.DB_SSL, env.DB_DEBUG)
  && await databaseHelper.initialize()
) {
  let server: http.Server | https.Server

  if (env.HTTPS) {
    https.globalAgent.maxSockets = Number.POSITIVE_INFINITY
    const privateKey = await fs.readFile(env.PRIVATE_KEY, 'utf8')
    const certificate = await fs.readFile(env.CERTIFICATE, 'utf8')
    const credentials: ServerOptions = { key: privateKey, cert: certificate }
    server = https.createServer(credentials, app)

    server.listen(env.PORT, () => {
      logger.info('HTTPS server is running on Port', env.PORT)
    })
  } else {
    server = app.listen(env.PORT, () => {
      logger.info('HTTP server is running on Port', env.PORT)
    })
  }

  const close = () => {
    logger.info('Gracefully stopping...')
    server.close(async () => {
      logger.info(`HTTP${env.HTTPS ? 'S' : ''} server closed`)
      await databaseHelper.close(true)
      logger.info('MongoDB connection closed')
      process.exit(0)
    })
  }

  ['SIGINT', 'SIGTERM', 'SIGQUIT'].forEach((signal) => process.on(signal, close))
}

Tout d’abord, nous créons un routeur express. Ensuite, on crée des routes en utilisant son nom, sa méthode, ses middlewares et son contrôleur.

routeNames contient les noms d'itinéraires de catégorieRoutes :

import express from 'express'
import compression from 'compression'
import helmet from 'helmet'
import nocache from 'nocache'
import cookieParser from 'cookie-parser'
import i18n from './lang/i18n'
import * as env from './config/env.config'
import cors from './middlewares/cors'
import allowedMethods from './middlewares/allowedMethods'
import userRoutes from './routes/userRoutes'
import categoryRoutes from './routes/categoryRoutes'
import productRoutes from './routes/productRoutes'
import cartRoutes from './routes/cartRoutes'
import orderRoutes from './routes/orderRoutes'
import notificationRoutes from './routes/notificationRoutes'
import deliveryTypeRoutes from './routes/deliveryTypeRoutes'
import paymentTypeRoutes from './routes/paymentTypeRoutes'
import settingRoutes from './routes/settingRoutes'
import stripeRoutes from './routes/stripeRoutes'
import wishlistRoutes from './routes/wishlistRoutes'
import * as helper from './common/helper'

const app = express()

app.use(helmet.contentSecurityPolicy())
app.use(helmet.dnsPrefetchControl())
app.use(helmet.crossOriginEmbedderPolicy())
app.use(helmet.frameguard())
app.use(helmet.hidePoweredBy())
app.use(helmet.hsts())
app.use(helmet.ieNoOpen())
app.use(helmet.noSniff())
app.use(helmet.permittedCrossDomainPolicies())
app.use(helmet.referrerPolicy())
app.use(helmet.xssFilter())
app.use(helmet.originAgentCluster())
app.use(helmet.crossOriginResourcePolicy({ policy: 'cross-origin' }))
app.use(helmet.crossOriginOpenerPolicy())

app.use(nocache())
app.use(compression({ threshold: 0 }))
app.use(express.urlencoded({ limit: '50mb', extended: true }))
app.use(express.json({ limit: '50mb' }))

app.use(cors())
app.options('*', cors())
app.use(cookieParser(env.COOKIE_SECRET))
app.use(allowedMethods)

app.use('/', userRoutes)
app.use('/', categoryRoutes)
app.use('/', productRoutes)
app.use('/', cartRoutes)
app.use('/', orderRoutes)
app.use('/', notificationRoutes)
app.use('/', deliveryTypeRoutes)
app.use('/', paymentTypeRoutes)
app.use('/', settingRoutes)
app.use('/', stripeRoutes)
app.use('/', wishlistRoutes)

i18n.locale = env.DEFAULT_LANGUAGE

await helper.mkdir(env.CDN_USERS)
await helper.mkdir(env.CDN_TEMP_USERS)
await helper.mkdir(env.CDN_CATEGORIES)
await helper.mkdir(env.CDN_TEMP_CATEGORIES)
await helper.mkdir(env.CDN_PRODUCTS)
await helper.mkdir(env.CDN_TEMP_PRODUCTS)

export default app

categoryController contient la principale logique métier concernant les catégories. Nous n'allons pas voir tout le code source du contrôleur car il est assez volumineux mais nous prendrons par exemple la fonction de création de contrôleur.

Ci-dessous le modèle de catégorie :

import express from 'express'
import multer from 'multer'
import routeNames from '../config/categoryRoutes.config'
import authJwt from '../middlewares/authJwt'
import * as categoryController from '../controllers/categoryController'

const routes = express.Router()

routes.route(routeNames.validate).post(authJwt.verifyToken, categoryController.validate)
routes.route(routeNames.checkCategory).get(authJwt.verifyToken, categoryController.checkCategory)
routes.route(routeNames.create).post(authJwt.verifyToken, categoryController.create)
routes.route(routeNames.update).put(authJwt.verifyToken, categoryController.update)
routes.route(routeNames.delete).delete(authJwt.verifyToken, categoryController.deleteCategory)
routes.route(routeNames.getCategory).get(authJwt.verifyToken, categoryController.getCategory)
routes.route(routeNames.getCategories).get(categoryController.getCategories)
routes.route(routeNames.getFeaturedCategories).get(categoryController.getFeaturedCategories)
routes.route(routeNames.searchCategories).get(authJwt.verifyToken, categoryController.searchCategories)
routes.route(routeNames.createImage).post([authJwt.verifyToken, multer({ storage: multer.memoryStorage() }).single('image')], categoryController.createImage)
routes.route(routeNames.updateImage).post([authJwt.verifyToken, multer({ storage: multer.memoryStorage() }).single('image')], categoryController.updateImage)
routes.route(routeNames.deleteImage).post(authJwt.verifyToken, categoryController.deleteImage)
routes.route(routeNames.deleteTempImage).post(authJwt.verifyToken, categoryController.deleteTempImage)

export default routes

Une catégorie a plusieurs valeurs. Une valeur par langue. Par défaut, les langues anglaise et française sont prises en charge.

Ci-dessous le modèle de valeur :

export default {
    validate: '/api/validate-category',
    checkCategory: '/api/check-category/:id',
    create: '/api/create-category',
    update: '/api/update-category/:id',
    delete: '/api/delete-category/:id',
    getCategory: '/api/category/:id/:language',
    getCategories: '/api/categories/:language/:imageRequired',
    getFeaturedCategories: '/api/featured-categories/:language/:size',
    searchCategories: '/api/search-categories/:language',
    createImage: '/api/create-category-image',
    updateImage: '/api/update-category-image/:id',
    deleteImage: '/api/delete-category-image/:id',
    deleteTempImage: '/api/delete-temp-category-image/:image',
}

Une valeur a un code de langue (ISO 639-1) et une valeur de chaîne.

Ci-dessous se trouve la fonction de création de contrôleur :

import { Schema, model } from 'mongoose'
import * as env from '../config/env.config'

const categorySchema = new Schema<env.Category>({
  values: {
    type: [Schema.Types.ObjectId],
    ref: 'Value',
    validate: (value: any) => Array.isArray(value),
  },
  image: {
    type: String,
  },
  featured: {
    type: Boolean,
    default: false,
  },
}, {
  timestamps: true,
  strict: true,
  collection: 'Category',
})

const Category = model<env.Category>('Category', categorySchema)

export default Category

Dans cette fonction, on récupère le corps de la requête, on parcourt les valeurs fournies dans le corps (une valeur par langue) et on crée une Value. Enfin, nous créons la catégorie en fonction des valeurs créées et du fichier image.

L'extrémité avant

Le frontend est une application Web construite avec Next.js et MUI. Depuis le frontend, l'utilisateur peut rechercher les produits disponibles, les ajouter au panier et procéder au paiement en fonction des modes de livraison et de paiement disponibles.

  • Le dossier ./frontend/public/ contient des actifs publics.
  • Le dossier ./frontend/src/styles/ contient des styles CSS.
  • Le dossier ./frontend/src/components/ contient des composants React.
  • ./frontend/src/lang/ contient des fichiers de paramètres régionaux.
  • Le dossier ./frontend/src/app/ contient les pages Next.js.
  • ./frontend/src/lib/ contient les actions du serveur.
  • ./frontend/next.config.ts est le fichier de configuration principal du frontend.

Le frontend a été créé avec create-next-app :

import { Schema, model } from 'mongoose'
import * as env from '../config/env.config'

const locationValueSchema = new Schema<env.Value>(
  {
    language: {
      type: String,
      required: [true, "can't be blank"],
      index: true,
      trim: true,
      lowercase: true,
      minLength: 2,
      maxLength: 2,
    },
    value: {
      type: String,
      required: [true, "can't be blank"],
      index: true,
      trim: true,
    },
  },
  {
    timestamps: true,
    strict: true,
    collection: 'Value',
  },
)

const Value = model<env.Value>('Value', locationValueSchema)

export default Value

Dans Next.js, une page est un composant React exporté à partir d'un fichier .js, .jsx, .ts ou .tsx dans le répertoire des pages. Chaque page est associée à un itinéraire en fonction de son nom de fichier.

Par défaut, Next.js pré-rend chaque page. Cela signifie que Next.js génère du HTML pour chaque page à l'avance, au lieu de tout faire via JavaScript côté client. Le pré-rendu peut entraîner de meilleures performances et un meilleur référencement.

Chaque HTML généré est associé au code JavaScript minimal nécessaire pour cette page. Lorsqu'une page est chargée par le navigateur, son code JavaScript s'exécute et rend la page entièrement interactive. (Ce processus est appelé hydratation.)

le frontend utilise le rendu côté serveur pour l'optimisation du référencement afin que les produits puissent être indexés par les moteurs de recherche.

Tableau de bord d'administration

Le tableau de bord d'administration est une application Web construite avec Next.js et MUI. Depuis le tableau de bord d'administration, les administrateurs peuvent gérer les catégories, les produits, les commandes et les utilisateurs. Lorsqu'une nouvelle commande est créée, l'utilisateur administrateur reçoit une notification et reçoit un e-mail.

  • Le dossier ./backend/public/ contient des actifs publics.
  • Le dossier ./backend/src/styles/ contient des styles CSS.
  • Le dossier ./backend/src/components/ contient des composants React.
  • ./backend/src/lang/ contient des fichiers de paramètres régionaux.
  • Le dossier ./backend/src/app/ contient les pages Next.js.
  • ./backend/src/lib/ contient les actions du serveur.
  • ./backend/next.config.ts est le fichier de configuration principal du backend.

Le tableau de bord d'administration a également été créé avec create-next-app :

import 'dotenv/config'
import process from 'node:process'
import fs from 'node:fs/promises'
import http from 'node:http'
import https, { ServerOptions } from 'node:https'
import * as env from './config/env.config'
import * as databaseHelper from './common/databaseHelper'
import app from './app'
import * as logger from './common/logger'

if (
  await databaseHelper.connect(env.DB_URI, env.DB_SSL, env.DB_DEBUG)
  && await databaseHelper.initialize()
) {
  let server: http.Server | https.Server

  if (env.HTTPS) {
    https.globalAgent.maxSockets = Number.POSITIVE_INFINITY
    const privateKey = await fs.readFile(env.PRIVATE_KEY, 'utf8')
    const certificate = await fs.readFile(env.CERTIFICATE, 'utf8')
    const credentials: ServerOptions = { key: privateKey, cert: certificate }
    server = https.createServer(credentials, app)

    server.listen(env.PORT, () => {
      logger.info('HTTPS server is running on Port', env.PORT)
    })
  } else {
    server = app.listen(env.PORT, () => {
      logger.info('HTTP server is running on Port', env.PORT)
    })
  }

  const close = () => {
    logger.info('Gracefully stopping...')
    server.close(async () => {
      logger.info(`HTTP${env.HTTPS ? 'S' : ''} server closed`)
      await databaseHelper.close(true)
      logger.info('MongoDB connection closed')
      process.exit(0)
    })
  }

  ['SIGINT', 'SIGTERM', 'SIGQUIT'].forEach((signal) => process.on(signal, close))
}

Ressources

  1. Aperçu
  2. Installation (auto-hébergé)
  3. Installation (Docker)
    1. Image Docker
    2. SSL
  4. Configuration de Stripe
  5. Exécuter à partir de la source
  6. Base de données de démonstration
    1. Windows, Linux et macOS
    2. Docker
  7. Changer la langue et la devise
  8. Ajouter une nouvelle langue
  9. Tests unitaires et couverture
  10. Journaux

C'est ça ! J'espère que vous avez apprécié la lecture.

Ce qui précède est le contenu détaillé de. pour plus d'informations, suivez d'autres articles connexes sur le site Web de PHP en chinois!

Déclaration:
Le contenu de cet article est volontairement contribué par les internautes et les droits d'auteur appartiennent à l'auteur original. Ce site n'assume aucune responsabilité légale correspondante. Si vous trouvez un contenu suspecté de plagiat ou de contrefaçon, veuillez contacter admin@php.cn