ホームページ > ウェブフロントエンド > jsチュートリアル > ゼロからストアフロントまで: 電子商取引サイトを構築する私の旅

ゼロからストアフロントまで: 電子商取引サイトを構築する私の旅

Susan Sarandon
リリース: 2024-11-10 02:54:02
オリジナル
224 人が閲覧しました

コンテンツ

  1. はじめに
  2. 技術スタック
  3. 概要
  4. API
  5. フロントエンド
  6. 管理者ダッシュボード
  7. リソース

ソースコード: https://github.com/aelassas/wexcommerce

デモ: https://wexcommerce.dynv6.net:8002

導入

創造的な自由と技術的な管理を重視する開発者にとって、Shopify のような従来の e コマース プラットフォームは制限があると感じることがあります。 Shopify のテンプレートは迅速なセットアップを提供し、Storefront API はある程度の柔軟性を提供しますが、どちらのソリューションも現代の開発者が切望する完全なアーキテクチャ上の自由を提供するものではありません。

このアイデアは、境界のない構築、つまりあらゆる側面を制御できる完全にカスタマイズ可能な e コマース サイトを構築したいという願望から生まれました。

  • UI/UX を所有する: テンプレートの制限と戦うことなく、独自の顧客エクスペリエンスをデザインします
  • バックエンドの制御: 要件に完全に一致するカスタム ビジネス ロジックとデータ構造を実装します
  • マスター DevOps: 優先ツールとワークフローを使用してアプリケーションをデプロイ、拡張、監視します
  • 自由に拡張: プラットフォームの制約や追加料金なしで、新しい機能や統合を追加します

技術スタック

これを可能にした技術スタックは次のとおりです:

  • Node.js
  • Next.js
  • MongoDB
  • ムイ
  • TypeScript
  • ストライプ
  • ドッカー

TypeScript には多くの利点があるため、設計上の重要な決定事項として TypeScript を使用することが決定されました。 TypeScript は強力な型指定、ツール、統合を提供し、その結果、デバッグとテストが容易な、高品質でスケーラブルで読みやすく保守しやすいコードが得られます。

私は強力なレンダリング機能のために Next.js を、柔軟なデータ モデリングのために MongoDB を、そして安全な支払い処理のために Stripe を選びました。

このスタックを選択すると、単にストアを構築するだけではなく、堅牢なオープンソース テクノロジーと成長する開発者コミュニティに支えられ、ニーズに合わせて進化できる基盤に投資することになります。

Next.js を使用してサイトを構築すると、ビジネスを拡大するための強固な基盤が得られます。コードの品質とドキュメントを維持しながら、パフォーマンス、セキュリティ、ユーザー エクスペリエンスに重点を置きます。定期的な更新と監視により、プラットフォームの競争力と信頼性が維持されます。

Next.js は、次の理由から優れた選択肢として際立っています。

  • 優れたパフォーマンス: 高速なページ読み込みとシームレスなユーザー エクスペリエンスを実現する組み込みの最適化
  • SEO の利点: 商品を見つけやすくするサーバー側のレンダリング機能
  • スケーラビリティ: ビジネスとともに成長するエンタープライズ対応アーキテクチャ
  • 豊富なエコシステム: 迅速な開発のためのライブラリとツールの膨大なコレクション
  • 開発者エクスペリエンス: ホットリロードと自動ルーティングを備えた直感的な開発ワークフロー

概要

フロントエンド

ユーザーはフロントエンドから、利用可能な製品を検索し、カートに製品を追加してチェックアウトできます。

以下はフロントエンドのランディング ページです:

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

以下はフロントエンドの検索ページです:

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

以下はサンプル製品ページです:

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

以下は製品画像の全画面表示です:

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

以下はカートページです:

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

以下はチェックアウトページです:

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

以下はサインイン ページです:

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

以下はサインアップページです:

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

以下はユーザーが注文を確認できるページです:

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

それだけです!これらはフロントエンドのメインページです。

管理者ダッシュボード

管理者は管理ダッシュボードから、カテゴリ、製品、ユーザー、注文を管理できます。

管理者は次の設定も管理できます:

  • ロケール設定: プラットフォームの言語 (英語またはフランス語) と通貨
  • 配信設定: 有効な配信方法とそれぞれの料金
  • 支払い設定: 有効な支払い方法 (クレジット カード、代金引換、電信送金)
  • 銀行設定: 電信送金用の銀行情報 (IBAN およびその他の情報)

以下はサインイン ページです:

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

以下は、管理者が注文を表示および管理できるダッシュボード ページです:

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

以下は管理者がカテゴリを管理するページです:

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

管理者が製品を表示および管理できるページは以下のとおりです:

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

以下は管理者が製品を編集するページです:

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

以下は製品画像の全画面表示です:

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

以下は設定ページです:

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

それだけです。これらは管理者ダッシュボードのメイン ページです。

API

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

この API は、MongoDB データベースへのアクセスを提供する Express を使用して RESTful API を公開する Node.js サーバー アプリケーションです。

API はフロントエンド、管理ダッシュボードによって使用され、モバイル アプリでも同様に使用されます。

API は、管理ダッシュボードとフロントエンドに必要なすべての機能を公開します。 API は MVC 設計パターンに従います。認証にはJWTが使用されます。商品や注文の管理に関連する機能など、認証が必要な機能と、認証されていないユーザー向けのカテゴリや利用可能な商品の取得など、認証を必要としない機能があります。

  • ./api/src/models/ フォルダーには MongoDB モデルが含まれています。
  • ./api/src/routes/ フォルダーには Express ルートが含まれています。
  • ./api/src/controllers/ フォルダーにはコントローラーが含まれています。
  • ./api/src/middlewares/ フォルダーにはミドルウェアが含まれています。
  • ./api/src/app.ts はルートがロードされるメインサーバーです。
  • ./api/src/index.ts は API のメイン エントリ ポイントです。

index.ts はメインサーバーにあります:

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))
}
ログイン後にコピー
ログイン後にコピー
ログイン後にコピー

これは、Node.js と Express を使用してサーバーを起動する TypeScript ファイルです。 dotenv、process、fs、http、https、mongoose、app などのいくつかのモジュールをインポートします。次に、MongoDB データベースとの接続を確立します。次に、HTTPS 環境変数が true に設定されているかどうかを確認し、true に設定されている場合は、https モジュールと提供された秘密キーと証明書を使用して HTTPS サーバーを作成します。それ以外の場合は、http モジュールを使用して HTTP サーバーを作成します。サーバーは、PORT 環境変数で指定されたポートで待機します。

close 関数は、終了信号を受信したときにサーバーを正常に停止するように定義されています。サーバーと MongoDB 接続を閉じ、ステータス コード 0 でプロセスを終了します。最後に、プロセスが SIGINT、SIGTERM、または SIGQUIT シグナルを受信したときに呼び出される close 関数を登録します。

app.ts は 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
ログイン後にコピー
ログイン後にコピー

まず、Express アプリを作成し、cors、compression、helmet、nocache などのミドルウェアをロードします。ヘルメットミドルウェアライブラリを利用して、さまざまなセキュリティ対策を設定します。また、productRoutes、orderRoutes、categoryRoutes、notificationRoutes、userRoutes など、アプリケーションのさまざまな部分のさまざまなルート ファイルもインポートします。最後に、Express ルートをロードし、アプリをエクスポートします。

API には 11 のルートがあります。各ルートには、MVC 設計パターンと SOLID 原則に従って独自のコントローラーがあります。以下は主なルートです:

  • userRoutes: ユーザーに関連する REST 機能を提供します
  • categoryRoutes: カテゴリに関連する REST 関数を提供します
  • productRoutes: 製品に関連する REST 関数を提供します
  • cartRoutes: カートに関連する REST 関数を提供します
  • wishlistRoutes: ウィッシュリストに関連する REST 関数を提供します
  • deliveryTypeRoutes: 配信方法に関連する REST 関数を提供します
  • paymentTypeRoutes: 支払い方法に関連する REST 関数を提供します
  • orderRoutes: 注文に関連する REST 関数を提供します
  • notificationRoutes: 通知に関連する REST 関数を提供します
  • settingRoutes: 設定に関連する REST 関数を提供します
  • StripeRoutes: Stripe ペイメントゲートウェイに関連する REST 機能を提供します

各ルートを一つずつ説明するつもりはありません。たとえば、categoryRoutes を取り上げ、それがどのように作成されたかを見てみましょう:

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))
}
ログイン後にコピー
ログイン後にコピー
ログイン後にコピー

まず、Express Router を作成します。次に、その名前、メソッド、ミドルウェア、コントローラーを使用してルートを作成します。

routeNames には categoryRoutes ルート名が含まれています:

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 には、カテゴリに関する主要なビジネス ロジックが含まれています。コントローラーのソース コードは非常に大きいため、すべてを見ることはできませんが、コントローラー関数の作成を例に説明します。

以下はカテゴリモデルです:

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
ログイン後にコピー

カテゴリには複数の値があります。言語ごとに 1 つの値。デフォルトでは、英語とフランス語がサポートされています。

以下は価値モデルです:

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',
}
ログイン後にコピー

値には言語コード (ISO 639-1) と文字列値が含まれます。

以下はコントローラー関数の作成です:

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
ログイン後にコピー

この関数では、リクエストの本文を取得し、本文で指定された値 (言語ごとに 1 つの値) を反復処理して、値を作成します。最後に、作成した値と画像ファイルに応じてカテゴリーを作成します。

フロントエンド

フロントエンドは、Next.js と MUI で構築された Web アプリケーションです。フロントエンドから、ユーザーは利用可能な商品を検索し、カートに追加し、利用可能な配送方法と支払い方法に応じてチェックアウトに進むことができます。

  • ./frontend/public/ フォルダーにはパブリック アセットが含まれています。
  • ./frontend/src/styles/ フォルダーには CSS スタイルが含まれています。
  • ./frontend/src/components/ フォルダーには React コンポーネントが含まれています。
  • ./frontend/src/lang/ にはロケール ファイルが含まれています。
  • ./frontend/src/app/ フォルダーには Next.js ページが含まれています。
  • ./frontend/src/lib/ にはサーバーアクションが含まれます。
  • ./frontend/next.config.ts はフロントエンドのメイン構成ファイルです。

フロントエンドは 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
ログイン後にコピー

Next.js では、ページは、pages ディレクトリ内の .js、.jsx、.ts、または .tsx ファイルからエクスポートされた React コンポーネントです。各ページは、ファイル名に基づいてルートに関連付けられます。

デフォルトでは、Next.js はすべてのページを事前レンダリングします。これは、クライアント側の JavaScript ですべてを実行するのではなく、Next.js が各ページの HTML を事前に生成することを意味します。プリレンダリングにより、パフォーマンスと SEO が向上します。

生成された各 HTML は、そのページに必要な最小限の JavaScript コードに関連付けられます。ページがブラウザによって読み込まれると、その JavaScript コードが実行され、ページが完全にインタラクティブになります。 (このプロセスを水和といいます。)

フロントエンドは SEO 最適化のためにサーバーサイド レンダリングを使用し、検索エンジンで商品のインデックスを作成できるようにします。

管理者ダッシュボード

管理ダッシュボードは、Next.js と MUI で構築された Web アプリケーションです。管理者は管理ダッシュボードから、カテゴリ、製品、注文、ユーザーを管理できます。新しい注文が作成されると、管理者ユーザーは通知を受け取り、電子メールを受け取ります。

  • ./backend/public/ フォルダーにはパブリック アセットが含まれています。
  • ./backend/src/styles/ フォルダーには CSS スタイルが含まれています。
  • ./backend/src/components/ フォルダーには React コンポーネントが含まれています。
  • ./backend/src/lang/ にはロケール ファイルが含まれています。
  • ./backend/src/app/ フォルダーには Next.js ページが含まれています。
  • ./backend/src/lib/ にはサーバーアクションが含まれます。
  • ./backend/next.config.ts はバックエンドのメイン構成ファイルです。

管理ダッシュボードも 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))
}
ログイン後にコピー
ログイン後にコピー
ログイン後にコピー

リソース

  1. 概要
  2. インストール中 (セルフホスト型)
  3. インストール(Docker)
    1. Docker イメージ
    2. SSL
  4. ストライプのセットアップ
  5. ソースから実行
  6. デモデータベース
    1. Windows、Linux、macOS
    2. ドッカー
  7. 言語と通貨を変更します
  8. 新しい言語を追加
  9. 単体テストとカバレッジ
  10. ログ

それだけです!楽しんで読んでいただければ幸いです。

以上がゼロからストアフロントまで: 電子商取引サイトを構築する私の旅の詳細内容です。詳細については、PHP 中国語 Web サイトの他の関連記事を参照してください。

ソース:dev.to
このウェブサイトの声明
この記事の内容はネチズンが自主的に寄稿したものであり、著作権は原著者に帰属します。このサイトは、それに相当する法的責任を負いません。盗作または侵害の疑いのあるコンテンツを見つけた場合は、admin@php.cn までご連絡ください。
著者別の最新記事
人気のチュートリアル
詳細>
最新のダウンロード
詳細>
ウェブエフェクト
公式サイト
サイト素材
フロントエンドテンプレート