İçeriğe geç

SSR Ayarlar

Bu sayfa @lentystyle/ssr içindeki iki ayrı config katmanını açıklar:

  • request-time render için LentySsrConfig
  • luis.config.mjs içindeki project-level ssr bloğu

Terminal window
pnpm add @lentystyle/ssr

LentySsrConfig, renderLentySsrSnapshot(), createLentySsrIntegration() ve diğer request-time SSR yüzeylerine geçen public config tipidir.

Bu katman:

  • runtime option default'larını tanımlar
  • HTML injection metadata'sını taşır
  • mode ve htmlGuardMode gibi alanları resolved biçimde tutar

interface LentySsrConfig {
mode?: 'static' | 'ssr'
htmlGuardMode?: 'ssr' | 'hybrid'
performance?: boolean
debug?: boolean
map?: boolean
lazy?: boolean
worker?: 'auto' | 'main' | 'worker'
assetBaseUrl?: string
globalCssHref?: string
bootstrapScriptSrc?: string
styleNonce?: string
scriptNonce?: string
runtimeOptions?: string | Partial<LentySsrRuntimeOptions>
/** @deprecated 0.2.0'da deprecate edildi ve ignore edilir. */
adapter?: 'none' | 'vue' | 'svelte' | 'react' | 'astro'
/** @deprecated 0.2.0'da deprecate edildi ve ignore edilir. */
rewritePolicy?: 'auto' | 'prefer-static' | 'prefer-runtime'
}
FieldDefault
mode'ssr'
htmlGuardMode'ssr' (proje runner'ı varsayılan olarak 'hybrid' kullanır)
debugfalse
performancefalse
mapfalse
lazyfalse
worker'auto'
assetBaseUrl/_hybrid
globalCssHrefnull
bootstrapScriptSrcnull
styleNoncenull
scriptNoncenull
output.payloadMode'inline-json' (proje config'i 'external-json''a geçebilir; aşağıya bakın)
import { createLentySsrIntegration } from '@lentystyle/ssr'
const ssr = createLentySsrIntegration({
mode: 'ssr',
globalCssHref: '/assets/site.css',
bootstrapScriptSrc: '/assets/browser-entry.js',
runtimeOptions: 'performance,!worker',
})

Bu örnekte:

  • ortak global CSS her render'da <link rel="stylesheet"> olarak enjekte edilir
  • bootstrap script her render'da enjekte edilir
  • runtime options çözümlemesi performance: true ve worker: 'main' verir

SSR'ın üretebileceği iki tag için iki bağımsız nonce alanı vardır:

const result = await renderLentySsrSnapshot(
{ styleNonce: 'STYLE_NONCE', bootstrapScriptSrc: '/entry.js', scriptNonce: 'SCRIPT_NONCE' },
input,
)
  • styleNonce yalnızca CSS boş değilse inline <style> tag'ine yazılır
  • scriptNonce yalnızca bootstrapScriptSrc verilmişse bootstrap <script src> tag'ine yazılır
  • inline JSON payload script'i hiçbir zaman çalıştırılabilir olmadığı için nonce almaz

Her iki nonce değeri de result.artifacts üzerinde (styleNonce, scriptNonce) geri yansıtılır; ilgili tag üretilmediyse null olur.


type LentySsrPayloadMode = 'inline-json' | 'external-json'
  • inline-json (varsayılan, request-time API'nin her zaman resolve olduğu tek mod): route payload'ı doğrudan <script type="application/json"> tag'i içine gömülür.
  • external-json: yalnızca project-level ssr.payloadMode ayarı üzerinden, lenty-ssr runner tarafından kullanılabilir. Runner her route için assetBaseUrl altına <route-token>.payload.json yazar; HTML de inline body yerine <script src="..."> referansı taşır.
export default defineLuisConfig({
ssr: { payloadMode: 'external-json' },
})

SSR request helper'ları kendi dahili guard policy'si ile gelir; config üzerinden guardPolicy geçmezsiniz. Html tarama modu htmlGuardMode alanını izler ve varsayılan olarak strict 'ssr' allowlist'ini kullanır.

SurfaceGuard behavior
renderLentySsrSnapshot()preset: 'strict', htmlMode: htmlGuardMode (varsayılan 'ssr')
createLentySsrIntegration().renderRequest()preset: 'strict', htmlMode: htmlGuardMode (varsayılan 'ssr')
createLentySsrFrameworkAdapter().render()preset: 'strict', htmlMode: htmlGuardMode (varsayılan 'ssr')

Kısa örnek:

import { renderLentySsrSnapshot } from '@lentystyle/ssr'
await renderLentySsrSnapshot({}, {
routeId: '/docs/',
html: '<html><head></head><body><div class="card"></div></body></html>',
sources: [
{
sourceId: 'docs.luis',
source: '.card { color: #0f172a; }',
},
],
})

Ek guard config vermeseniz bile bu çağrı request envelope'u validate eder ve downstream hybrid compile adımında strict doğrulamayı korur.


Injection sırasıyla şu konumları dener:

  1. <!-- lenty-ssr --> placeholder — html bu comment'i içeriyorsa, üretilen tag'ler yerine yazılır (comment kaybolur; yalnız ilk eşleşme kullanılır)
  2. </head> — placeholder yoksa, tag'ler head close'un hemen önüne eklenir
  3. prepend — ikisi de yoksa, tag'ler html'in en başına eklenir
<html>
<head>
<title>Docs</title>
<!-- lenty-ssr -->
</head>
...

createLentySsrProd() ve createLentySsrProdFromProjectConfig() aynı cache seçeneklerini kabul eder:

interface LentySsrProdOptions {
maxEntries?: number // varsayılan 100, default in-memory store için geçerlidir
ttlMs?: number // varsayılan undefined -> entry'ler kendiliğinden expire olmaz
cacheStore?: LentySsrCacheStore<LentySsrProdRenderResult> // varsayılan: yerleşik in-memory store
}

Integration ayrıca cache yönetim metodları sunar:

await prod.invalidate(routeId) // yalnız o route'un cache entry'lerini unutur
await prod.clear() // her şeyi unutur (hit/miss sayaçları SIFIRLANMAZ)
const stats = await prod.stats() // { hitCount, missCount, entryCount }
interface LentySsrCacheStore<TValue> {
get: (key: string) => Promise<{ value: TValue; expiresAt: number | null } | undefined>
set: (key: string, entry: { value: TValue; expiresAt: number | null }) => Promise<void>
delete: (key: string) => Promise<void>
clear: () => Promise<void>
keys?: () => Promise<string[]> // opsiyonel; key enumerate edemeyen store'lar atlayabilir
}

Cache'i varsayılan process-local Map yerine Redis vb. paylaşılan bir store ile desteklemek için bunu implemente edin:

import { createLentySsrProd } from '@lentystyle/ssr'
const prod = createLentySsrProd({}, {
ttlMs: 60_000,
cacheStore: {
async get(key) { /* ... */ },
async set(key, entry) { /* ... */ },
async delete(key) { /* ... */ },
async clear() { /* ... */ },
// keys() yok -> bu store için eviction ve kesin entryCount atlanır
},
})

Bu, yukarıdaki production result cache'inden ayrı, daha küçük bir cache — yalnızca .luis metninin tekrar parse edilmesini atlar, route başına CSS işini değil.

import { createLentySsrCompileCache, createLentySsrProd, getLentySsrCompileCacheStats } from '@lentystyle/ssr'
const compileCache = createLentySsrCompileCache({ maxEntries: 500 }) // varsayılan 500
const prod = createLentySsrProd({}, { compileCache })
getLentySsrCompileCacheStats(compileCache) // { entryCount, maxEntries }
  • .luis source içeriğinin hash'iyle key'lenir, bu yüzden her zaman doğrudur: aynı .luis dosyasını paylaşan iki farklı route tam olarak bir cache entry'si üretir
  • her route'un html'ine karşı observed-rule eşleştirmesi her render'da her zaman taze çalışır — cache asla eski veya eksik CSS'e yol açmaz, yalnızca değişmemiş .luis metninin yeniden parse edilmesini atlar
  • createLentySsrProd(), createLentySsrProdIntegration(), createLentySsrFromProjectConfig() ve createLentySsrProdFromProjectConfig() compileCache verilmediğinde otomatik olarak bir tane oluşturur
  • aynı örneği birden fazla integration'a vererek parse sonuçlarını aralarında paylaştırabilirsiniz
  • renderLentySsrSnapshot() ve diğer tek seferlik doğrudan çağrılar varsayılan olarak compile cache kullanmaz

SSR içindeki runtime option merge sırası sabittir:

package defaults
-> config.debug / performance / map / lazy / worker
-> config.runtimeOptions
-> source.runtimeOptions
  1. Temel default'lar uygulanır

    {
    debug: false,
    performance: false,
    map: false,
    lazy: false,
    worker: 'auto',
    }
  2. Top-level config flag'leri uygulanır

    debug, performance, map, lazy ve worker bu aşamada uygulanır.

  3. config.runtimeOptions patch'i uygulanır

    String veya object patch, top-level flag'leri override eder.

  4. Source-level override uygulanır

    input.sources[].runtimeOptions, config-level sonucu source bazında override eder.

runtimeOptions: 'debug,performance,!worker'

Sonuç:

{
debug: true,
performance: true,
map: false,
lazy: false,
worker: 'main',
}

Desteklenen token'lar:

  • debug, performance, map, lazy
  • !debug, !performance, !map, !lazy
  • worker -> worker: 'worker'
  • !worker -> worker: 'main'
const result = await renderLentySsrSnapshot(
{ runtimeOptions: 'debug,worker' },
{
routeId: '/docs/',
html,
sources: [
{
sourceId: 'docs.luis',
source,
runtimeOptions: '!debug,lazy,!worker',
},
],
},
)

Bu source için final runtime options:

{
debug: false,
performance: false,
map: false,
lazy: true,
worker: 'main',
}

Request-level default ve source-level override birlikte

Section titled “Request-level default ve source-level override birlikte”

Config:

const config = {
runtimeOptions: 'debug,performance,worker',
}

Source:

const input = {
routeId: '/docs/',
html: '<html><head></head><body><div class="card"></div></body></html>',
sources: [
{
sourceId: 'docs.luis',
source: '.card { color: #0f172a; }',
runtimeOptions: '!debug,lazy,!worker',
},
],
}

Bu source için final runtime options:

{
debug: false,
performance: true,
map: false,
lazy: true,
worker: 'main',
}

Project-level SSR config tipi LuisSsrProjectConfig'dir. LentySsrConfig alanlarını devralır ve preview veya project-level alanlar ekler.

import { defineLuisConfig } from '@lentystyle/core'
export default defineLuisConfig({
ssr: {
mode: 'ssr',
outDirName: 'dist-ssr',
maxEntries: 100,
defaultRuntimeOptions: '',
include: ['docs/**', '**/*.html'],
exclude: ['admin/**'],
},
})
FieldPurposeDefault
htmlDirNameRunner'ın okuduğu build edilmiş HTML girdi dizininin adı'dist'
outDirNamePreview HTML kök dizininin adı'dist-ssr'
maxEntriesProd helper için app-level cache limiti100
defaultRuntimeOptionsRunner'ın otomatik keşfettiği ve config'te eşlenen route source'larına merge edilen varsayılan runtime option string'i''
includeDahil edilecek relative HTML path pattern'leri[]
excludeAtlanacak relative HTML path pattern'leri[]
routesRequest-time renderRoute() için route-pattern -> .luis source eşlemeleri[]
payloadModeRunner tarafından render edilen route'lar için payload taşıma modu ('inline-json' | 'external-json')'inline-json'

routes girdileri { match, sourceDirs?, sources? } şeklindedir: match '/docs/**' gibi bir route id pattern'i (veya listesi), sourceDirs .luis dosyaları için taranacak dizinler, sources ise açık dosya listesidir — ikisi de config dizinine göredir. Tam request-time tarifleri için Framework'ler sayfasına bakın.

import { defineLuisConfig } from '@lentystyle/core'
export default defineLuisConfig({
ssr: {
mode: 'ssr',
outDirName: 'dist-ssr',
defaultRuntimeOptions: 'performance',
include: ['docs/**'],
},
})

Bu kurulumda defaultRuntimeOptions, auto-discovered source'lara ortak bir baseline verir. Bir source farklı davranmalıysa source-level runtimeOptions ile override edin.


loadLuisSsrProjectConfig(configOrPath?, overrides?)

Section titled “loadLuisSsrProjectConfig(configOrPath?, overrides?)”
import { loadLuisSsrProjectConfig } from '@lentystyle/ssr'
const config = await loadLuisSsrProjectConfig(undefined, { cwd: appDir })

Bu helper:

  • luis.config.mjs dosyasını yükler
  • ssr bloğunu okur
  • request-level config alanlarını çözümler
  • outDirName, maxEntries, include ve exclude gibi project-level default'ları uygular

Validation kuralları:

  • config dosyası gerçek bir ssr object export etmiyorsa throw eder
  • include ve exclude verildiyse string array olmalıdır
  • outDirName boş olamaz ve / ile \ içeremez
{
configPath: '.../luis.config.mjs',
configDir: '.../apps/site',
outDirName: 'dist-ssr',
outDir: '.../apps/site/dist-ssr',
maxEntries: 100,
defaultRuntimeOptions: '',
include: [],
exclude: [],
runtimeOptions: {
debug: false,
performance: false,
map: false,
lazy: false,
worker: 'auto',
},
}

shouldProcessLuisSsrProjectHtmlFile(htmlFilePath, config) üretilen HTML yolunu config.outDir altındaki relative path'e çevirir ve pattern match yapar.

import {
loadLuisSsrProjectConfig,
shouldProcessLuisSsrProjectHtmlFile,
} from '@lentystyle/ssr'
const config = await loadLuisSsrProjectConfig(undefined, { cwd: appDir })
shouldProcessLuisSsrProjectHtmlFile(
`${appDir}/dist-ssr/docs/index.html`,
config,
)

Match kuralları:

  • include boşsa dosya varsayılan olarak dahil edilir
  • include boş değilse en az bir pattern eşleşmelidir
  • sonra exclude eşleşirse dosya reddedilir
ssr: {
include: ['docs/**', 'blog/**'],
exclude: ['blog/drafts/**'],
}

Desteklenen küçük-glob davranışı:

  • *
  • **
  • ?

Path normalization her zaman / kullanır.


  • adapter ve rewritePolicy 0.2.0'da deprecate edildi ve ignore edilir
  • request-time LentySsrConfig her zaman output.payloadMode'u 'inline-json''a resolve eder; 'external-json' yalnız project-level ssr.payloadMode ayarı üzerinden (runner-only) erişilebilir
  • browser runtime'ın external-json payload dosyalarını fetch edip boot etmesi henüz uygulanmadı
  • defaultRuntimeOptions lenty-ssr runner tarafından ve ssr.routes'tan renderRoute() tarafından otomatik uygulanır; low-level render API bunu doğrudan okumaz
  • include ve exclude yalnızca generated HTML relative path'lerine göre karar verir; source discovery runner'a aittir
  • maxEntries eviction ve kesin stats().entryCount cache store'un keys() desteklemesini gerektirir; desteklemeyen custom store'lar (örn. bazı remote cache'ler) ikisini de atlar