Rumah >hujung hadapan web >tutorial js >Dari Sifar ke Etalase: Perjalanan Saya Membina Tapak E-dagang

Dari Sifar ke Etalase: Perjalanan Saya Membina Tapak E-dagang

Susan Sarandon
Susan Sarandonasal
2024-11-10 02:54:02219semak imbas

Kandungan

  1. Pengenalan
  2. Timbunan Teknologi
  3. Ikhtisar Pantas
  4. API
  5. Hadapan
  6. Papan Pemuka Pentadbir
  7. Sumber

Kod sumber: https://github.com/aelassas/wexcommerce

Demo: https://wexcommerce.dynv6.net:8002

pengenalan

Bagi pembangun yang menghargai kebebasan kreatif dan kawalan teknikal, platform e-Dagang tradisional seperti Shopify boleh berasa terhad. Walaupun templat Shopify menawarkan persediaan pantas, dan API Storefront mereka memberikan sedikit fleksibiliti, kedua-dua penyelesaian tidak memberikan kebebasan seni bina lengkap yang diidamkan oleh pembangun moden.

Idea itu muncul daripada keinginan untuk membina tanpa sempadan – tapak eDagang yang boleh disesuaikan sepenuhnya di mana setiap aspek berada dalam kawalan anda:

  • Miliki UI/UX: Reka pengalaman pelanggan yang unik tanpa melawan had templat
  • Kawal Bahagian Belakang: Laksanakan logik perniagaan tersuai dan struktur data yang sepadan dengan keperluan
  • Master DevOps: Sebarkan, skala dan pantau aplikasi dengan alatan dan aliran kerja pilihan
  • Perluas Secara Bebas: Tambahkan ciri dan penyepaduan baharu tanpa kekangan platform atau bayaran tambahan

Timbunan Teknologi

Berikut ialah susunan teknologi yang membolehkannya:

  • Node.js
  • Next.js
  • MongoDB
  • MUI
  • Skrip Jenis
  • Belang
  • Pelabuh

Keputusan reka bentuk utama telah dibuat untuk menggunakan TypeScript kerana banyak kelebihannya. TypeScript menawarkan penaipan, perkakasan dan penyepaduan yang kuat, menghasilkan kod berkualiti tinggi, berskala, lebih mudah dibaca dan boleh diselenggara yang mudah untuk nyahpepijat dan diuji.

Saya memilih Next.js kerana keupayaan pemaparan yang berkuasa, MongoDB untuk pemodelan data fleksibel dan Stripe untuk pemprosesan pembayaran yang selamat.

Dengan memilih tindanan ini, anda bukan sekadar membina kedai – anda melabur dalam asas yang boleh berkembang mengikut keperluan anda, disokong oleh teknologi sumber terbuka yang teguh dan komuniti pembangun yang semakin berkembang.

Membina tapak dengan Next.js menyediakan asas yang kukuh untuk menskalakan perniagaan. Fokus pada prestasi, keselamatan dan pengalaman pengguna sambil mengekalkan kualiti dan dokumentasi kod. Kemas kini dan pemantauan yang kerap akan memastikan platform kekal kompetitif dan boleh dipercayai.

Next.js menonjol sebagai pilihan yang sangat baik kerana:

  • Prestasi Unggul: Pengoptimuman terbina dalam untuk pemuatan halaman yang pantas dan pengalaman pengguna yang lancar
  • Kelebihan SEO: Keupayaan pemaparan bahagian pelayan yang memastikan produk anda boleh ditemui
  • Skalabiliti: Seni bina sedia perusahaan yang berkembang bersama perniagaan anda
  • Ekosistem Kaya: Koleksi perpustakaan dan alatan yang banyak untuk pembangunan pesat
  • Pengalaman Pembangun: Aliran kerja pembangunan intuitif dengan muat semula panas dan penghalaan automatik

Gambaran keseluruhan pantas

Bahagian hadapan

Dari bahagian hadapan, pengguna boleh mencari produk yang tersedia, menambah produk ke troli dan pembayaran.

Di bawah ialah halaman pendaratan bahagian hadapan:

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

Di bawah ialah halaman carian bahagian hadapan:

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

Di bawah ialah contoh halaman produk:

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

Di bawah ialah paparan skrin penuh imej produk:

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

Di bawah ialah halaman troli:

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

Di bawah ialah halaman pembayaran:

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

Di bawah ialah halaman log masuk:

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

Di bawah ialah halaman pendaftaran:

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

Di bawah ialah halaman di mana pengguna boleh melihat pesanannya:

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

Itu sahaja! Itu adalah halaman utama bahagian hadapan.

Papan Pemuka Pentadbir

Daripada papan pemuka pentadbir, pentadbir boleh mengurus kategori, produk, pengguna dan pesanan.

Pentadbir juga boleh mengurus tetapan berikut:

  • Tetapan Tempatan: Bahasa platform (Bahasa Inggeris atau Perancis) dan mata wang
  • Tetapan Penghantaran: Kaedah penghantaran didayakan dan kos setiap satu
  • Tetapan Pembayaran: Kaedah pembayaran didayakan (Kad kredit, Tunai semasa penghantaran atau pindahan wayar)
  • Tetapan Bank: Maklumat bank untuk pindahan kawat (IBAN dan maklumat lain)

Di bawah ialah halaman log masuk:

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

Di bawah ialah halaman papan pemuka dari mana pentadbir boleh melihat dan mengurus pesanan:

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

Di bawah ialah halaman dari mana pentadbir menguruskan kategori:

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

Di bawah ialah halaman dari mana pentadbir boleh melihat dan mengurus produk:

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

Di bawah ialah halaman dari mana pentadbir mengedit produk:

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

Di bawah ialah paparan skrin penuh imej produk:

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

Di bawah ialah halaman tetapan:

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

Itu sahaja. Itu adalah halaman utama papan pemuka admin.

API

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

Api ialah aplikasi pelayan Node.js yang mendedahkan API RESTful menggunakan Express yang memberikan akses kepada pangkalan data MongoDB.

Api digunakan oleh bahagian hadapan, papan pemuka pentadbir dan akan digunakan oleh apl mudah alih juga.

Api mendedahkan semua fungsi yang diperlukan untuk papan pemuka pentadbir dan bahagian hadapan. Api mengikut corak reka bentuk MVC. JWT digunakan untuk pengesahan. Terdapat beberapa fungsi yang memerlukan pengesahan seperti fungsi yang berkaitan dengan menguruskan produk dan pesanan, dan lain-lain yang tidak memerlukan pengesahan seperti mendapatkan semula kategori dan produk yang tersedia untuk pengguna yang tidak disahkan:

  • ./api/src/models/ folder mengandungi model MongoDB.
  • ./api/src/routes/ folder mengandungi laluan Ekspres.
  • ./api/src/controllers/ folder mengandungi pengawal.
  • ./api/src/middlewares/ folder mengandungi middlewares.
  • ./api/src/app.ts ialah pelayan utama tempat laluan dimuatkan.
  • ./api/src/index.ts ialah titik masuk utama api.

index.ts berada dalam pelayan utama:

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))
}

Ini ialah fail TypeScript yang memulakan pelayan menggunakan Node.js dan Express. Ia mengimport beberapa modul termasuk dotenv, proses, fs, http, https, mongoose dan aplikasi. Ia kemudian mewujudkan sambungan dengan pangkalan data MongoDB. Ia kemudian menyemak sama ada pembolehubah persekitaran HTTPS ditetapkan kepada benar, dan jika ya, mencipta pelayan HTTPS menggunakan modul https dan kunci peribadi serta sijil yang disediakan. Jika tidak, ia mencipta pelayan HTTP menggunakan modul http. Pelayan mendengar pada port yang dinyatakan dalam pembolehubah persekitaran PORT.

Fungsi tutup ditakrifkan untuk menghentikan pelayan dengan anggun apabila isyarat penamatan diterima. Ia menutup pelayan dan sambungan MongoDB, dan kemudian keluar dari proses dengan kod status 0. Akhir sekali, ia mendaftarkan fungsi tutup untuk dipanggil apabila proses menerima isyarat SIGINT, SIGTERM atau SIGQUIT.

app.ts ialah titik masuk utama 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

Pertama sekali, kami mencipta apl Ekspres dan memuatkan perisian tengah seperti cors, mampatan, topi keledar dan nocache. Kami menyediakan pelbagai langkah keselamatan menggunakan perpustakaan middleware topi keledar. Kami juga mengimport pelbagai fail laluan untuk bahagian aplikasi yang berbeza seperti productRoutes, orderRoutes, categoryRoutes, notificationRoutes, userRoutes. Akhir sekali, kami memuatkan laluan Ekspres dan apl eksport.

Terdapat 11 laluan dalam api. Setiap laluan mempunyai pengawal sendiri mengikut corak reka bentuk MVC dan prinsip SOLID. Di bawah adalah laluan utama:

  • userRoutes: Menyediakan fungsi REST yang berkaitan dengan pengguna
  • categoryRoutes: Menyediakan fungsi REST yang berkaitan dengan kategori
  • productRoutes: Menyediakan fungsi REST yang berkaitan dengan produk
  • CartRoutes: Menyediakan fungsi REST yang berkaitan dengan troli
  • WishlistRoutes: Menyediakan fungsi REST yang berkaitan dengan senarai hajat
  • deliveryTypeRoutes: Menyediakan fungsi REST yang berkaitan dengan kaedah penghantaran
  • paymentTypeRoutes: Menyediakan fungsi REST yang berkaitan dengan kaedah pembayaran
  • orderRoutes: Menyediakan fungsi REST yang berkaitan dengan pesanan
  • Laluan pemberitahuan: Menyediakan fungsi REST yang berkaitan dengan pemberitahuan
  • settingRoutes: Menyediakan fungsi REST yang berkaitan dengan tetapan
  • stripeRoutes: Menyediakan fungsi REST yang berkaitan dengan gerbang pembayaran Stripe

Kami tidak akan menerangkan setiap laluan satu demi satu. Kami akan mengambil, sebagai contoh, kategoriLaluan dan melihat cara ia dibuat:

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))
}

Pertama sekali, kami mencipta Penghala Ekspres. Kemudian, kami mencipta laluan menggunakan namanya, kaedahnya, perisian tengah dan pengawalnya.

Nama laluan mengandungi kategoriNama laluan:

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 mengandungi logik perniagaan utama mengenai kategori. Kami tidak akan melihat semua kod sumber pengawal kerana ia agak besar tetapi kami akan mengambil fungsi pengawal sebagai contoh.

Di bawah ialah model Kategori:

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

Kategori mempunyai berbilang nilai. Satu nilai bagi setiap bahasa. Secara lalai, bahasa Inggeris dan Perancis disokong.

Di bawah ialah model Nilai:

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',
}

Nilai mempunyai kod bahasa (ISO 639-1) dan nilai rentetan.

Di bawah ialah cipta fungsi pengawal:

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

Dalam fungsi ini, kami mendapatkan semula kandungan permintaan, kami mengulangi nilai yang disediakan dalam kandungan (satu nilai setiap bahasa) dan kami mencipta Nilai. Akhir sekali, kami mencipta kategori bergantung pada nilai yang dicipta dan fail imej.

Bahagian hadapan

Halaman hadapan ialah aplikasi web yang dibina dengan Next.js dan MUI. Dari bahagian hadapan, pengguna boleh mencari produk yang tersedia, menambahkannya pada troli dan meneruskan pembayaran bergantung pada penghantaran dan kaedah pembayaran yang tersedia.

  • ./frontend/public/ folder mengandungi aset awam.
  • ./frontend/src/styles/ folder mengandungi gaya CSS.
  • ./frontend/src/komponen/ folder mengandungi komponen React.
  • ./frontend/src/lang/ mengandungi fail setempat.
  • ./frontend/src/app/ folder mengandungi halaman Next.js.
  • ./frontend/src/lib/ mengandungi tindakan pelayan.
  • ./frontend/next.config.ts ialah fail konfigurasi utama bahagian hadapan.

Halaman hadapan telah dibuat dengan 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

Dalam Next.js, halaman ialah Komponen Reaksi yang dieksport daripada fail .js, .jsx, .ts atau .tsx dalam direktori halaman. Setiap halaman dikaitkan dengan laluan berdasarkan nama failnya.

Secara lalai, Next.js memprapaparkan setiap halaman. Ini bermakna Next.js menjana HTML untuk setiap halaman terlebih dahulu, dan bukannya melakukan semuanya oleh JavaScript pihak pelanggan. Prapemarahan boleh menghasilkan prestasi dan SEO yang lebih baik.

Setiap HTML yang dijana dikaitkan dengan kod JavaScript minimum yang diperlukan untuk halaman tersebut. Apabila halaman dimuatkan oleh penyemak imbas, kod JavaScriptnya berjalan dan menjadikan halaman itu interaktif sepenuhnya. (Proses ini dipanggil penghidratan.)

bahagian hadapan menggunakan Rendering Sisi Pelayan untuk pengoptimuman SEO supaya produk boleh diindeks oleh enjin carian.

Papan Pemuka Pentadbir

Papan pemuka pentadbir ialah aplikasi web yang dibina dengan Next.js dan MUI. Daripada papan pemuka pentadbir, pentadbir boleh mengurus kategori, produk, pesanan dan pengguna. Apabila pesanan baharu dibuat, pengguna pentadbir mendapat pemberitahuan dan menerima e-mel.

  • ./backend/public/ folder mengandungi aset awam.
  • ./backend/src/styles/ folder mengandungi gaya CSS.
  • ./backend/src/components/ folder mengandungi komponen React.
  • ./backend/src/lang/ mengandungi fail setempat.
  • ./backend/src/app/ folder mengandungi halaman Next.js.
  • ./backend/src/lib/ mengandungi tindakan pelayan.
  • ./backend/next.config.ts ialah fail konfigurasi utama bahagian belakang.

Papan pemuka pentadbir juga telah dibuat dengan 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))
}

Sumber

  1. Ikhtisar
  2. Memasang (Dihoskan sendiri)
  3. Memasang (Docker)
    1. Imej Docker
    2. SSL
  4. Sediakan Jalur
  5. Larikan dari Sumber
  6. Pangkalan Data Demo
    1. Windows, Linux dan macOS
    2. Pelabuh
  7. Tukar Bahasa dan Mata Wang
  8. Tambah Bahasa Baharu
  9. Ujian Unit dan Liputan
  10. Balak

Itu sahaja! Saya harap anda seronok membaca.

Atas ialah kandungan terperinci Dari Sifar ke Etalase: Perjalanan Saya Membina Tapak E-dagang. Untuk maklumat lanjut, sila ikut artikel berkaitan lain di laman web China PHP!

Kenyataan:
Kandungan artikel ini disumbangkan secara sukarela oleh netizen, dan hak cipta adalah milik pengarang asal. Laman web ini tidak memikul tanggungjawab undang-undang yang sepadan. Jika anda menemui sebarang kandungan yang disyaki plagiarisme atau pelanggaran, sila hubungi admin@php.cn