Sunucu Tarafı İşleme

Carats, @carats/ssr paketi üzerinden otomatik sunucu tarafı işlemeyi (SSR) sağlar.

Sunucu Giriş Noktası

Sunucu giriş noktası, @carats/ssr'dan defineServerEntry kullanılarak src/server/entrypoint.ts içinde tanımlanır. Paylaşılan facet'leri bağlar, culet'leri kaydeder ve sunucu eklentisinin kullandığı render ile getServerProps fonksiyonlarını sunar.

import { defineServerEntry } from '@carats/ssr';
import facets from '../client/facets.cara';

export default defineServerEntry(facets);

Giriş Noktasının Sunduğu Şeyler

`defineServerEntry` tarafından döndürülen nesne, sunucu eklentisinin yönettiği şeydir:

  • `render(req)`, istenen URL için facet'i çözer, sayfa bileşenini çalıştırır ve işlenmiş `html` ile toplanan `head` etiketlerini birlikte döndürür.
  • `getServerProps(req)`, istenen URL için culet'i çözer ve değerini döndürür; rotanın culet'i yoksa `undefined` döner.
  • `facets` paylaşılan facet nesnesidir, `culets` ise `culet` ve `seat` tarafından kurulan kayıt defteridir.

Varsayılan dışa aktarımın kendisinin giriş noktası olmasının nedeni budur: Express eklentisi bu fonksiyonları her istek için çağırır.

Culet Tanımlama

Culet'ler @carats/ssr'dan culet fonksiyonuyla tanımlanır. Yalnızca bir rotanın gerçekten sunucu tarafı bir prop'a ihtiyacı varsa ve veri tek bir GET isteğiyle alınabiliyorsa bir culet tanımlayın. Geri çağrı, isteği rota parametreleri, çerezler, başlıklar, sorgu ve metot dahil olmak üzere alır.

import { culet } from '@carats/ssr';

culet<User>('/profile', (req) => {
    return {
        id: '1',
        name: 'Alexander Whitmore',
        username: 'awhitmore',
        email: 'a.whitmore@vault.io',
        phone: '+1 (212) 555-0193',
        website: 'whitmore.capital',
    };
});

Genel parametre isteğe bağlıdır ama korunmaya değer: dönüş değerinin onu tüketen sayfanın prop'larıyla eşleşmesini sağlayan odur.

Culet'leri Oturtma

Kendi dosyasında oluşturulan bir culet, sunucu giriş noktasında seat fonksiyonuyla kaydedilmelidir. Oturtma culet'i sarmalamaz veya yeniden oluşturmaz; aynı fonksiyonu döndürür, böylece satır içinde kullanılabilir.

import { culet, seat } from '@carats/ssr';
import getTradeData from './culets/trade';

seat(getTradeData);

Giriş noktası içinde satır içi bildirilen bir culet kendini kaydeder, bu yüzden `seat` çağrısına ihtiyaç duymaz. `src/server/culets` üzerinden içe aktarılan bir culet ise kendi modülünde `culet()` ile oluşturulmuştur ve bir kez oturtulmalıdır. Oturtulmuş bir culet'i başka bir `culet()` çağrısıyla sarmalamayın; bu, aynı işleyiciyi ikinci bir rota altında kaydeder.

Express Entegrasyonu

Carats, @carats/express üzerinden Express ile entegre edilir. Dışa aktarılan carats fonksiyonu sayfaları işleyen, sunucu prop'larını çözen ve derlenmiş istemci varlıklarını sunan bir Router döndürür; bu yüzden app.use ile bağlanır. Bu paket Express 5 gerektirir.

Sunucu Giriş Noktası

import { culet, defineServerEntry, seat } from '@carats/ssr';
import facets from '../client/facets.cara';
import getTradeData from './culets/trade';

seat(getTradeData);

culet<User>('/profile', () => {
    return {
        id: '1',
        name: 'Alexander Whitmore',
        username: 'awhitmore',
        email: 'a.whitmore@vault.io',
        phone: '+1 (212) 555-0193',
        website: 'whitmore.capital',
    };
});

export default defineServerEntry(facets);

Express Uygulaması

import { carats } from '@carats/express'
import express from 'express'

const app = express()
const port = process.env.PORT || 5173

app.use(carats())

const server = app.listen(port, () => {
    console.log(`Server started at http://localhost:${port}`)
})

export default server;

Middleware'i, `carats()` yutması gerekmeyen rotalar ve statik işleyicilerden sonra çalışacak şekilde sıralayın. Eklenti bir Express `Router` döndürür; bu yüzden bir rota olarak kaydedilmek yerine `app.use` ile bağlanır.

Sunucu Vite Yapılandırması

Sunucu paketi src/server/entrypoint.ts kaynağından dist/server dizinine derlenir. publicDir devre dışı bırakılır, çünkü statik varlıklar istemci derlemesine aittir.

import { defineConfig } from 'vite'
import path from 'path'

export default defineConfig({
  publicDir: false,
  build: {
    ssr: path.resolve(__dirname, 'src/server/entrypoint.ts'),
    outDir: path.resolve(__dirname, 'dist/server'),
    emptyOutDir: true,
    minify: true,
    rollupOptions: {
      treeshake: true
    }
  }
})

Tam Sunucu Giriş Noktası Örneği

// src/server/culets/trade.ts
import { culet } from '@carats/ssr';

export default culet<TradeData>('/trade/:symbol', async (req) => {
    const symbol = req.params.symbol;
    if (!symbol) {
        throw new Error('Symbol is required');
    }
    return {
        symbol: symbol.toUpperCase(),
        price: '$67,234.18',
        change24h: '+2.34%',
        volume: '$28.4B',
        high24h: '$68,102.50',
        low24h: '$65,890.00',
        orderBook: { bids: [], asks: [] },
    };
});
// src/server/entrypoint.ts
import { culet, defineServerEntry, seat } from '@carats/ssr';
import facets from '../client/facets.cara';
import getTradeData from './culets/trade';

seat(getTradeData);

culet<User>('/profile', () => {
    return {
        id: '1',
        name: 'Alexander Whitmore',
        username: 'awhitmore',
        email: 'a.whitmore@vault.io',
        phone: '+1 (212) 555-0193',
        website: 'whitmore.capital',
    };
});

export default defineServerEntry(facets);

Facet rotası ile culet rotasının `:symbol` parametresi dahil birebir aynı dize olduğuna dikkat edin. Uyuşmazlık, burnished bir sayfanın verisiz işlenmesinin en yaygın nedenidir.

Tip Tanımları

import { CaratsRequest } from '@carats/core';
import { Facets } from '@carats/render';

interface CaratsServerEntry {
    render: (req: CaratsRequest<never>) => Promise<{
        html?: string;
        head?: string;
    }>;
    getServerProps: <T = any>(req: CaratsRequest<never>) => Promise<T> | T;
    facets: Facets;
    culets: Record<string, Culet>;
}

type CuletArgs = Omit<CaratsRequest, 'data'> & {
    params: Record<string, string>;
};

type Culet<T = any> = (request: CuletArgs) => T;

declare const seat: <T extends Culet>(f: T) => T;
declare function culet<T = any>(route: string, culet: Culet<T>): Culet<T>;
declare function defineServerEntry(facets: Facets): CaratsServerEntry;