Menyediakan Tema dalam Aplikasi SSR React
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:
- serverTheme - Digunakan untuk menggunakan kelas yang betul pada tag.
- 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('<html lang="en">', `<html lang="en"> <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)
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 <html> 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> }
// ./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={viteLogo} className="logo" alt="Vite logo" /> </a> <a href="https://react.dev" target="_blank" rel="noreferrer"> <img src={reactLogo} className="logo react" alt="React logo" /> </a> </div> <h1>Vite + React</h1> <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} />) }
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!

Alat AI Hot

Undresser.AI Undress
Apl berkuasa AI untuk mencipta foto bogel yang realistik

AI Clothes Remover
Alat AI dalam talian untuk mengeluarkan pakaian daripada foto.

Undress AI Tool
Gambar buka pakaian secara percuma

Clothoff.io
Penyingkiran pakaian AI

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

Artikel Panas

Alat panas

Notepad++7.3.1
Editor kod yang mudah digunakan dan percuma

SublimeText3 versi Cina
Versi Cina, sangat mudah digunakan

Hantar Studio 13.0.1
Persekitaran pembangunan bersepadu PHP yang berkuasa

Dreamweaver CS6
Alat pembangunan web visual

SublimeText3 versi Mac
Perisian penyuntingan kod peringkat Tuhan (SublimeText3)

Topik panas

Soalan dan penyelesaian yang sering ditanya untuk percetakan tiket kertas terma depan dalam pembangunan front-end, percetakan tiket adalah keperluan umum. Walau bagaimanapun, banyak pemaju sedang melaksanakan ...

JavaScript adalah asas kepada pembangunan web moden, dan fungsi utamanya termasuk pengaturcaraan yang didorong oleh peristiwa, penjanaan kandungan dinamik dan pengaturcaraan tak segerak. 1) Pengaturcaraan yang didorong oleh peristiwa membolehkan laman web berubah secara dinamik mengikut operasi pengguna. 2) Penjanaan kandungan dinamik membolehkan kandungan halaman diselaraskan mengikut syarat. 3) Pengaturcaraan Asynchronous memastikan bahawa antara muka pengguna tidak disekat. JavaScript digunakan secara meluas dalam interaksi web, aplikasi satu halaman dan pembangunan sisi pelayan, sangat meningkatkan fleksibiliti pengalaman pengguna dan pembangunan silang platform.

Tidak ada gaji mutlak untuk pemaju Python dan JavaScript, bergantung kepada kemahiran dan keperluan industri. 1. Python boleh dibayar lebih banyak dalam sains data dan pembelajaran mesin. 2. JavaScript mempunyai permintaan yang besar dalam perkembangan depan dan stack penuh, dan gajinya juga cukup besar. 3. Faktor mempengaruhi termasuk pengalaman, lokasi geografi, saiz syarikat dan kemahiran khusus.

Pembelajaran JavaScript tidak sukar, tetapi ia mencabar. 1) Memahami konsep asas seperti pembolehubah, jenis data, fungsi, dan sebagainya. 2) Pengaturcaraan asynchronous tuan dan melaksanakannya melalui gelung acara. 3) Gunakan operasi DOM dan berjanji untuk mengendalikan permintaan tak segerak. 4) Elakkan kesilapan biasa dan gunakan teknik debugging. 5) Mengoptimumkan prestasi dan mengikuti amalan terbaik.

Perbincangan mengenai realisasi kesan animasi tatal dan elemen Parallax dalam artikel ini akan meneroka bagaimana untuk mencapai yang serupa dengan laman web rasmi Shiseido (https://www.shiseido.co.jp/sb/wonderland/) ... ...

Trend terkini dalam JavaScript termasuk kebangkitan TypeScript, populariti kerangka dan perpustakaan moden, dan penerapan webassembly. Prospek masa depan meliputi sistem jenis yang lebih berkuasa, pembangunan JavaScript, pengembangan kecerdasan buatan dan pembelajaran mesin, dan potensi pengkomputeran IoT dan kelebihan.

Bagaimana cara menggabungkan elemen array dengan ID yang sama ke dalam satu objek dalam JavaScript? Semasa memproses data, kita sering menghadapi keperluan untuk mempunyai id yang sama ...

Perbincangan mendalam mengenai punca-punca utama perbezaan dalam output konsol.log. Artikel ini akan menganalisis perbezaan hasil output fungsi Console.log dalam sekeping kod dan menerangkan sebab -sebab di belakangnya. � ...
