cari
Rumahhujung hadapan webtutorial jsMenyediakan Tema dalam Aplikasi SSR React

Setting Up Themes in SSR React Applications

Bayangkan melawati tapak web yang menyesuaikan dengan pilihan anda dengan lancar—bertukar antara tema terang, gelap dan berasaskan sistem dengan lancar.

Artikel ini meneruskan siri saya tentang SSR dengan React. Dalam artikel asas, kami meneroka konfigurasi sedia pengeluaran, manakala dalam teknik lanjutan, kami menangani cabaran seperti ralat penghidratan. Kini, kami akan melangkah lebih jauh dengan melaksanakan sokongan tema teguh yang disepadukan dengan lancar dengan SSR.

Jadual Kandungan

  • Tema dan SSR
  • Perlaksanaan
    • Pasang Ketergantungan
    • Tambahkan kuki pada Binaan Pelayan
    • Gunakan Tema pada Pelayan
    • Kendalikan Tema pada Pelanggan
  • Kesimpulan

Tema dan SSR

Isu utama ialah Denyar Awal Tema Salah (FOIT).

Pada asasnya, tema hanyalah tentang menukar pembolehubah CSS. Dalam kebanyakan kes, anda akan menggunakan tiga tema:

  • Cahaya: Set lalai pembolehubah CSS.
  • Gelap: Digunakan apabila tag mempunyai kelas gelap.
  • Sistem: Bertukar secara automatik berdasarkan pilihan sistem pengguna, menggunakan (skim-warna-pilihan: gelap) pertanyaan media untuk menentukan sama ada tema harus gelap atau terang.

Secara lalai, pelayan akan memaparkan HTML dengan tema ringan dan menghantarnya ke penyemak imbas. Jika pengguna lebih suka tema gelap, mereka akan melihat perubahan tema yang boleh dilihat pada pemuatan halaman pertama, yang mengganggu pengalaman pengguna.

Terdapat dua cara utama untuk menyelesaikan isu ini:

  • Tambahkan teg dalam HTML pada pelayan dan tetapkan kelas secara dinamik pada klien.
  • Gunakan kuki untuk menyimpan pilihan tema pengguna dan tetapkan kelas pada pelayan.

Penyelesaian pertama ialah cara pakej tema seterusnya berfungsi (Jan 2025). Dalam artikel ini, anda akan melaksanakan pendekatan berasaskan kuki untuk memastikan pengendalian tema yang lancar dalam aplikasi SSR anda.

Perlaksanaan

Untuk melaksanakan tema, anda akan menggunakan dua kuki:

  1. serverTheme - Digunakan untuk menggunakan kelas yang betul pada tag.
  2. Tema pelanggan - Digunakan untuk mengendalikan ralat penghidratan.

Pelanggan sentiasa menetapkan kedua-dua kuki, memastikan pelayan dapat memaparkan tema yang sesuai dengan betul pada permintaan seterusnya.

Panduan ini dibina berdasarkan konsep yang diperkenalkan dalam artikel sebelumnya, Membina Aplikasi Reaksi SSR Sedia Pengeluaran, yang boleh anda temui dipautkan di bahagian bawah. Untuk kesederhanaan, pemalar dan jenis yang dikongsi tidak dibuat di sini, tetapi anda boleh menemui pelaksanaannya dalam repositori contoh.

Pasang Ketergantungan

Pasang pakej yang diperlukan untuk pengendalian kuki:

pnpm add cookie js-cookie

Jenis pemasangan untuk js-cookie:

pnpm add -D @types/js-cookie

Jika anda tidak menggunakan penghala tindak balas dalam apl anda, anda boleh menggunakan pakej kuki sebagai devDependencies.

Tambahkan kuki pada Binaan Pelayan

Kemas kini fail konfigurasi tsup anda:

// ./tsup.config.ts
import { defineConfig } from 'tsup'

export default defineConfig({
  entry: ['server'],
  outDir: 'dist/server',
  target: 'node22',
  format: ['cjs'],
  clean: true,
  minify: true,
  external: ['lightningcss', 'esbuild', 'vite'],
  noExternal: [
    'express',
    'sirv',
    'compression',
    'cookie', // Include the cookie in the server build
  ],
})

Gunakan Tema pada Pelayan

Tentukan Pemalar Tema

// ./server/constants.ts
export const CLIENT_THEME_COOKIE_KEY = 'clientTheme'
export const SERVER_THEME_COOKIE_KEY = 'serverTheme'

export enum Theme {
  Light = 'light',
  Dark = 'dark',
  System = 'system'
}

Gunakan Kelas Tema untuk Teg

Buat fungsi utiliti untuk menggunakan kelas tema yang betul pada tag berdasarkan kuki Tema pelayan:

// ./server/lib/applyServerTheme.ts
import { parse } from 'cookie'
import { Request } from 'express'
import { SERVER_THEME_COOKIE_KEY, Theme } from '../constants'

export function applyServerTheme(req: Request, html: string): string {
  const cookies = parse(req.headers.cookie || '')
  const theme = cookies?.[SERVER_THEME_COOKIE_KEY]

  if (theme === Theme.Dark) {
    return html.replace('', `



<h4>
  
  
  Retrieve the Client Theme Cookie
</h4>

<p>Create a utility function to retrieve the clientTheme cookie<br>
</p>

<pre class="brush:php;toolbar:false">// ./server/getClientTheme.ts
import { parse } from 'cookie'
import { Request } from 'express'
import { CLIENT_THEME_COOKIE_KEY, Theme } from '../constants'

export function getClientTheme(req: Request) {
  const cookies = parse(req.headers.cookie || '')

  return cookies?.[CLIENT_THEME_COOKIE_KEY] as Theme | undefined
}

Kemas kini Konfigurasi Pelayan untuk Tema

Tatarajah Pembangunan:

// ./server/dev.ts
import fs from 'fs'
import path from 'path'
import { Application } from 'express'
import { HTML_KEY } from './constants'
import { applyServerTheme } from './lib/applyServerTheme'
import { getClientTheme } from './lib/getClientTheme'

const HTML_PATH = path.resolve(process.cwd(), 'index.html')
const ENTRY_SERVER_PATH = path.resolve(process.cwd(), 'src/entry-server.tsx')

export async function setupDev(app: Application) {
  const vite = await (
    await import('vite')
  ).createServer({
    root: process.cwd(),
    server: { middlewareMode: true },
    appType: 'custom',
  })

  app.use(vite.middlewares)

  app.get('*', async (req, res, next) => {
    try {
      let html = fs.readFileSync(HTML_PATH, 'utf-8')
      html = await vite.transformIndexHtml(req.originalUrl, html)

      const { render } = await vite.ssrLoadModule(ENTRY_SERVER_PATH)
      // send Client Theme from cookie to render
      const appHtml = await render(getClientTheme(req))

      // Apply Server theme on template html
      html = applyServerTheme(req, html)
      html = html.replace(HTML_KEY, appHtml)

      res.status(200).set({ 'Content-Type': 'text/html' }).end(html)
    } catch (e) {
      vite.ssrFixStacktrace(e as Error)
      console.error((e as Error).stack)
      next(e)
    }
  })
}

Konfigurasi Pengeluaran:

// ./server/prod.ts
import fs from 'fs'
import path from 'path'
import compression from 'compression'
import { Application } from 'express'
import sirv from 'sirv'
import { HTML_KEY } from './constants'
import { applyServerTheme } from './lib/applyServerTheme'
import { getClientTheme } from './lib/getClientTheme'

const CLIENT_PATH = path.resolve(process.cwd(), 'dist/client')
const HTML_PATH = path.resolve(process.cwd(), 'dist/client/index.html')
const ENTRY_SERVER_PATH = path.resolve(process.cwd(), 'dist/ssr/entry-server.js')

export async function setupProd(app: Application) {
  app.use(compression())
  app.use(sirv(CLIENT_PATH, { extensions: [] }))

  app.get('*', async (req, res, next) => {
    try {
      let html = fs.readFileSync(HTML_PATH, 'utf-8')

      const { render } = await import(ENTRY_SERVER_PATH)
      // send Client Theme from cookie to render
      const appHtml = await render(getClientTheme(req))

      // Apply Server theme on template html
      html = applyServerTheme(req, html)
      html = html.replace(HTML_KEY, appHtml)

      res.status(200).set({ 'Content-Type': 'text/html' }).end(html)
    } catch (e) {
      console.error((e as Error).stack)
      next(e)
    }
  })
}

Mengendalikan Tema pada Klien

Tentukan Pemalar

Pemalar pendua untuk kegunaan pelanggan atau alihkannya ke folder kongsi

// ./src/constants.ts
export const SSR = import.meta.env.SSR

export const CLIENT_THEME_COOKIE_KEY = 'clientTheme'
export const SERVER_THEME_COOKIE_KEY = 'serverTheme'

export enum Theme {
  Light = 'light',
  Dark = 'dark',
  System = 'system',
}

Cipta Konteks Tema

Sediakan konteks React untuk mengurus keadaan tema dan menyediakan kaedah pengurusan tema:

// ./src/theme/context.ts
import { createContext, useContext } from 'react'
import { Theme } from '../constants'

export type ThemeContextState = {
  theme: Theme
  setTheme: (theme: Theme) => void
}

export const ThemeContext = createContext<themecontextstate>({
  theme: Theme.System,
  setTheme: () => null,
})

export const useThemeContext = () => useContext(ThemeContext)
</themecontextstate>

Laksanakan Utiliti Tema

// ./src/theme/lib.ts
import Cookies from 'js-cookie'
import { CLIENT_THEME_COOKIE_KEY, SERVER_THEME_COOKIE_KEY, SSR, Theme } from '../constants'

// Resolve the system theme using the `prefers-color-scheme` media query
export function resolveSystemTheme() {
  if (SSR) return Theme.Light
  return window.matchMedia('(prefers-color-scheme: dark)').matches ? Theme.Dark : Theme.Light
}

// Update the theme cookies and set appropriate class to 
export function updateTheme(theme: Theme) {
  if (SSR) return

  const resolvedTheme = theme === Theme.System ? resolveSystemTheme() : theme

  Cookies.set(CLIENT_THEME_COOKIE_KEY, theme)
  Cookies.set(SERVER_THEME_COOKIE_KEY, resolvedTheme)

  window.document.documentElement.classList.toggle('dark', resolvedTheme === Theme.Dark)
}

// Get the default theme from cookies
export function getDefaultTheme(): Theme {
  if (SSR) return Theme.System
  const theme = (Cookies.get(CLIENT_THEME_COOKIE_KEY) as Theme) || Theme.System

  updateTheme(theme)
  return theme
}

Buat Penyedia Tema

// ./src/theme/Provider.tsx
import { PropsWithChildren, useState } from 'react'
import { Theme } from '../constants'
import { ThemeContext } from './context'
import { getDefaultTheme, updateTheme } from './lib'

type Props = PropsWithChildren & {
  defaultTheme?: Theme // Handle theme for SSR
}

export function ThemeProvider({ children, defaultTheme }: Props) {
  const [theme, setTheme] = useState<theme>(defaultTheme || getDefaultTheme())

  const handleSetTheme = (theme: Theme) => {
    setTheme(theme)
    updateTheme(theme)
  }

  return <themecontext value="{{" theme settheme: handlesettheme>{children}</themecontext>
}
</theme>
// ./src/theme/index.ts
export { ThemeProvider } from './Provider'
export { useThemeContext } from './context'

Gunakan Konteks Tema dalam Komponen

// ./src/App.tsx
import reactLogo from './assets/react.svg'
import viteLogo from '/vite.svg'
import Card from './Card'
import { Theme } from './constants'
import { ThemeProvider } from './theme'

import './App.css'

// Theme from Server Entry
type AppProps = {
  theme?: Theme
}

function App({ theme }: AppProps) {
  return (
    <themeprovider defaulttheme="{theme}">
      <div>
        <a href="https://vite.dev" target="_blank" rel="noreferrer">
          <img src="%7BviteLogo%7D" classname="logo" alt="Vite logo">
        </a>
        <a href="https://react.dev" target="_blank" rel="noreferrer">
          <img src="%7BreactLogo%7D" classname="logo react" alt="React logo">
        </a>
      </div>
      <h1 id="Vite-React">Vite + React</h1>
      <card></card>
      <p classname="read-the-docs">Click on the Vite and React logos to learn more</p>
    </themeprovider>
  )
}

export default App

Buat Komponen Kad

// ./src/Card.tsx
import { useState } from 'react'
import { Theme } from './constants'
import { useThemeContext } from './theme'

function Card() {
  const { theme, setTheme } = useThemeContext()
  const [count, setCount] = useState(0)

  return (
    <div classname="card">
      <button onclick="{()"> setCount((count) => count + 1)}>count is {count}</button>
      <p>
        Edit <code>src/App.tsx</code> and save to test HMR
      </p>
      <div>
        Themes:{' '}
        <select value="{theme}" onchange="{(event)"> setTheme(event.target.value as Theme)}>
          <option value="{Theme.System}">System</option>
          <option value="{Theme.Light}">Light</option>
          <option value="{Theme.Dark}">Dark</option>
        </select>
      </div>
    </div>
  )
}

export default Card

Selesaikan Ralat Penghidratan

Lepaskan tema kepada kaedah pemaparan pelayan untuk memastikan HTML yang dijana pelayan sepadan dengan pemaparan sebelah klien:

import { renderToString } from 'react-dom/server'
import App from './App'
import { Theme } from './constants'

export function render(theme: Theme) {
  return renderToString(<app theme="{theme}"></app>)
}

Tambah Gaya

:root {
    color: #242424;
    background-color: rgba(255, 255, 255, 0.87);
}

:root.dark {
    color: rgba(255, 255, 255, 0.87);
    background-color: #242424;
}

Kesimpulan

Dalam artikel ini, kami menangani cabaran untuk melaksanakan tema lancar dalam aplikasi SSR React. Dengan menggunakan kuki dan menyepadukan kedua-dua logik sisi klien dan sisi pelayan, kami mencipta sistem yang teguh yang menyokong tema terang, gelap dan berasaskan sistem tanpa ralat penghidratan atau gangguan pengalaman pengguna.

Terokai Kod

  • Contoh: react-ssr-themes-example
  • Mendarat dengan SSR: pendaratan profesional

Artikel Berkaitan

Ini adalah sebahagian daripada siri saya tentang SSR dengan React. Nantikan lebih banyak artikel!

  • Membina Aplikasi SSR React Sedia Pengeluaran
  • Teknik SSR React Terperinci dengan Penstriman dan Data Dinamik
  • Menyediakan Tema dalam Aplikasi SSR React

Kekal Terhubung

Saya sentiasa terbuka untuk maklum balas, kerjasama atau membincangkan idea teknologi — jangan ragu untuk menghubungi kami!

  • Portfolio: maxh1t.xyz
  • E-mel: m4xh17@gmail.com

Atas ialah kandungan terperinci Menyediakan Tema dalam Aplikasi SSR React. 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
Python vs JavaScript: Analisis Perbandingan untuk PemajuPython vs JavaScript: Analisis Perbandingan untuk PemajuMay 09, 2025 am 12:22 AM

Perbezaan utama antara Python dan JavaScript ialah sistem jenis dan senario aplikasi. 1. Python menggunakan jenis dinamik, sesuai untuk pengkomputeran saintifik dan analisis data. 2. JavaScript mengamalkan jenis yang lemah dan digunakan secara meluas dalam pembangunan depan dan stack penuh. Kedua -duanya mempunyai kelebihan mereka sendiri dalam pengaturcaraan dan pengoptimuman prestasi yang tidak segerak, dan harus diputuskan mengikut keperluan projek ketika memilih.

Python vs JavaScript: Memilih alat yang sesuai untuk pekerjaanPython vs JavaScript: Memilih alat yang sesuai untuk pekerjaanMay 08, 2025 am 12:10 AM

Sama ada untuk memilih Python atau JavaScript bergantung kepada jenis projek: 1) Pilih Python untuk Sains Data dan Tugas Automasi; 2) Pilih JavaScript untuk pembangunan front-end dan penuh. Python disukai untuk perpustakaannya yang kuat dalam pemprosesan data dan automasi, sementara JavaScript sangat diperlukan untuk kelebihannya dalam interaksi web dan pembangunan stack penuh.

Python dan javascript: memahami kekuatan masing -masingPython dan javascript: memahami kekuatan masing -masingMay 06, 2025 am 12:15 AM

Python dan JavaScript masing -masing mempunyai kelebihan mereka sendiri, dan pilihan bergantung kepada keperluan projek dan keutamaan peribadi. 1. Python mudah dipelajari, dengan sintaks ringkas, sesuai untuk sains data dan pembangunan back-end, tetapi mempunyai kelajuan pelaksanaan yang perlahan. 2. JavaScript berada di mana-mana dalam pembangunan front-end dan mempunyai keupayaan pengaturcaraan tak segerak yang kuat. Node.js menjadikannya sesuai untuk pembangunan penuh, tetapi sintaks mungkin rumit dan rawan kesilapan.

Inti JavaScript: Adakah ia dibina di atas C atau C?Inti JavaScript: Adakah ia dibina di atas C atau C?May 05, 2025 am 12:07 AM

Javascriptisnotbuiltoncorc; it'saninterpretedlanguagethatrunsonenginesoftenwritteninc .1) javascriptwasdesignedasalightweight, interpratedlanguageforwebbrowsers.2)

Aplikasi JavaScript: Dari Front-End ke Back-EndAplikasi JavaScript: Dari Front-End ke Back-EndMay 04, 2025 am 12:12 AM

JavaScript boleh digunakan untuk pembangunan front-end dan back-end. Bahagian depan meningkatkan pengalaman pengguna melalui operasi DOM, dan back-end mengendalikan tugas pelayan melalui Node.js. 1. Contoh front-end: Tukar kandungan teks laman web. 2. Contoh backend: Buat pelayan Node.js.

Python vs JavaScript: Bahasa mana yang harus anda pelajari?Python vs JavaScript: Bahasa mana yang harus anda pelajari?May 03, 2025 am 12:10 AM

Memilih Python atau JavaScript harus berdasarkan perkembangan kerjaya, keluk pembelajaran dan ekosistem: 1) Pembangunan Kerjaya: Python sesuai untuk sains data dan pembangunan back-end, sementara JavaScript sesuai untuk pembangunan depan dan penuh. 2) Kurva Pembelajaran: Sintaks Python adalah ringkas dan sesuai untuk pemula; Sintaks JavaScript adalah fleksibel. 3) Ekosistem: Python mempunyai perpustakaan pengkomputeran saintifik yang kaya, dan JavaScript mempunyai rangka kerja front-end yang kuat.

Rangka Kerja JavaScript: Menguasai Pembangunan Web ModenRangka Kerja JavaScript: Menguasai Pembangunan Web ModenMay 02, 2025 am 12:04 AM

Kuasa rangka kerja JavaScript terletak pada pembangunan yang memudahkan, meningkatkan pengalaman pengguna dan prestasi aplikasi. Apabila memilih rangka kerja, pertimbangkan: 1.

Hubungan antara JavaScript, C, dan penyemak imbasHubungan antara JavaScript, C, dan penyemak imbasMay 01, 2025 am 12:06 AM

Pengenalan Saya tahu anda mungkin merasa pelik, apa sebenarnya yang perlu dilakukan oleh JavaScript, C dan penyemak imbas? Mereka seolah -olah tidak berkaitan, tetapi sebenarnya, mereka memainkan peranan yang sangat penting dalam pembangunan web moden. Hari ini kita akan membincangkan hubungan rapat antara ketiga -tiga ini. Melalui artikel ini, anda akan mempelajari bagaimana JavaScript berjalan dalam penyemak imbas, peranan C dalam enjin pelayar, dan bagaimana mereka bekerjasama untuk memacu rendering dan interaksi laman web. Kita semua tahu hubungan antara JavaScript dan penyemak imbas. JavaScript adalah bahasa utama pembangunan front-end. Ia berjalan secara langsung di penyemak imbas, menjadikan laman web jelas dan menarik. Adakah anda pernah tertanya -tanya mengapa Javascr

See all articles

Alat AI Hot

Undresser.AI Undress

Undresser.AI Undress

Apl berkuasa AI untuk mencipta foto bogel yang realistik

AI Clothes Remover

AI Clothes Remover

Alat AI dalam talian untuk mengeluarkan pakaian daripada foto.

Undress AI Tool

Undress AI Tool

Gambar buka pakaian secara percuma

Clothoff.io

Clothoff.io

Penyingkiran pakaian AI

Video Face Swap

Video Face Swap

Tukar muka dalam mana-mana video dengan mudah menggunakan alat tukar muka AI percuma kami!

Alat panas

SublimeText3 Linux versi baharu

SublimeText3 Linux versi baharu

SublimeText3 Linux versi terkini

Versi Mac WebStorm

Versi Mac WebStorm

Alat pembangunan JavaScript yang berguna

ZendStudio 13.5.1 Mac

ZendStudio 13.5.1 Mac

Persekitaran pembangunan bersepadu PHP yang berkuasa

MantisBT

MantisBT

Mantis ialah alat pengesan kecacatan berasaskan web yang mudah digunakan yang direka untuk membantu dalam pengesanan kecacatan produk. Ia memerlukan PHP, MySQL dan pelayan web. Lihat perkhidmatan demo dan pengehosan kami.

SublimeText3 versi Cina

SublimeText3 versi Cina

Versi Cina, sangat mudah digunakan