This page collects the settings you typically need for @lentystyle/hybrid. The goal is to answer these questions without dropping into low-level APIs:
- which file do I create
- which fields do I configure
- how do build and dev behave
- what are the defaults
- when do I stay config-driven, when do I drop to low-level guard control
Minimal Setup
Section titled “Minimal Setup”Select your package manager for the install command:
pnpm add @lentystyle/hybridnpm install @lentystyle/hybridyarn add @lentystyle/hybridInstall
@lentystyle/hybridCreate
luis.config.mjsin the project rootDefine the
hybridblockRun the build script
Minimal luis.config.mjs Example
Section titled “Minimal luis.config.mjs Example”import { defineLuisConfig } from '@lentystyle/core/config'
export default defineLuisConfig({ hybrid: { buildMode: 'initial', sourceRoots: ['./public', './dist'], luisOutputDir: './dist/_hybrid', assetBaseUrl: '/_hybrid', globalCssFileName: 'lentystyle-global.css', defaultRuntimeOptions: '', },})Build script:
{ "scripts": { "build": "astro build && pnpm exec lentystyle-hybrid build" }}Generic dev middleware example:
import { defineMiddleware } from 'astro:middleware'import { createHybridProjectDevMiddleware } from '@lentystyle/hybrid'
const hybridDev = await createHybridProjectDevMiddleware()
export const onRequest = defineMiddleware((context, next) => hybridDev(context.request, () => next()),)Defaults
Section titled “Defaults”If a field is omitted, the core defaults are:
| Field | Default |
|---|---|
buildMode | 'initial' |
htmlOutputDir | './dist' |
assetBaseUrl | '' |
globalCssFileName | 'lentystyle-global.css' |
globalManifestFileName | 'lentystyle-global.manifest.json' |
writeRouteCssArtifacts | false |
defaultRuntimeOptions | undefined |
hybridOptions | undefined |
rewrite | 'auto' |
include | [] |
exclude | [] |
In practice:
- without
buildModethe default'initial'mode runs: route HTML scanning, single CSS + single manifest, and generated global CSS links in source-bearing HTML files - without
htmlOutputDir, hybrid reads route HTML from./dist - without
assetBaseUrlrewritten asset URLs get no extra prefix - without
globalCssFileNamethe shared generated CSS is written aslentystyle-global.css - without
globalManifestFileNamethe global manifest is written aslentystyle-global.manifest.json - without
writeRouteCssArtifacts, route mode does not write per-route.cssfiles - without
defaultRuntimeOptionssource-leveldata-luisvalues apply on their own
Key Settings
Section titled “Key Settings”| Field | What it does | When you need it |
|---|---|---|
buildMode | 'initial' (default): route HTML scan with one CSS + manifest and generated CSS link injection. 'global': source-only compile, single CSS + manifest, plus generated CSS link injection when htmlOutputDir is explicit. 'route': per-route payloads | Always; use explicit 'global' when route HTML output is not available |
htmlOutputDir | Framework build output folder containing route HTML files | Override it when your output folder is not ./dist |
sourceRoots | Roots where .luis source discovery runs | Always |
luisOutputDir | Directory for generated LentyStyle CSS, manifest, and payload artifacts | Always |
assetBaseUrl | Asset prefix inside rewritten HTML | If you want a custom prefix instead of a flat URL |
globalCssFileName | Shared generated CSS file name | If the default lentystyle-global.css name conflicts with your asset naming |
globalManifestFileName | Global manifest JSON file name | If the default lentystyle-global.manifest.json name conflicts |
writeRouteCssArtifacts | In route mode, also write one route-scoped .css file per processed route | Only for consumers that fetch route CSS assets directly |
defaultRuntimeOptions | User-visible runtime behavior merged into discovered .luis sources | If generated manifests should request debug, performance, map, lazy, or worker |
hybridOptions | Terminal-visible hybrid compile and rewrite diagnostics | If build/dev should print hybrid debug or performance logs without changing user runtime output |
rewrite | Rewrite policy for source .luis tags | If you want to control runtime-vs-static output |
include / exclude | Which HTML or .luis candidates to process | If you want to process only part of the project |
When Settings Are Applied
Section titled “When Settings Are Applied”In build mode runHybridProjectBuild() or the CLI first loads the config:
buildMode: 'initial'(default): route HTML files are scanned, non-observed plus initially matched?/?!observed rules are written to one global CSS file, non-matching observed rules stay in the runtime manifest, and source-bearing HTML files receive the generated global CSS link with observed-only source markersbuildMode: 'global': all.luissources compiled against empty HTML, singleglobalCssFileName+ singleglobalManifestFileNamewritten underluisOutputDir; all observed rules stay in the runtime manifest. IfhtmlOutputDiris explicitly configured and exists, the generated global CSS link and observed-only source markers are also written into route HTML filesbuildMode: 'route': route-aware HTML mode reads route HTML fromhtmlOutputDirand writes per-route payload artifacts underluisOutputDirincludeandexcludefilter which candidates are scanned- route-scoped CSS files are skipped unless
writeRouteCssArtifacts: true
In dev mode createHybridProjectDevIntegration() or createHybridProjectDevMiddleware() reuses the same config:
- produces in-memory assets
buildMode: 'global'serves one startup-compiled CSS + manifest from configured.luisrootsbuildMode: 'initial'compiles the current dev route response into one shared in-memory CSS + manifest instead of scanning every route on navigationbuildMode: 'route'rewrites HTML responses per routesourceRoots,defaultRuntimeOptions,hybridOptions,rewrite,include, andexcludebehave the same as in build- serves the in-memory shared generated CSS at
assetBaseUrl/globalCssFileName
Built-in Guard Defaults and Override Point
Section titled “Built-in Guard Defaults and Override Point”Hybrid guard behavior varies by the active flow.
| Flow | Built-in guard behavior |
|---|---|
| Global mode | preset: 'trusted-build', allowedLocalRoots: sourceRoots |
| Initial mode and route-aware HTML mode | preset: 'balanced', htmlMode: 'hybrid' |
Manual compileHybridBundle({...}) | Your provided guardPolicy if any |
Default config-driven flow:
import { runHybridProjectBuild } from '@lentystyle/hybrid'
await runHybridProjectBuild()This call reads the hybrid block and chooses global, initial, or route behavior from buildMode.
Custom policy example:
import { compileHybridBundle } from '@lentystyle/hybrid/node'
await compileHybridBundle({ routeId: '/docs/', html: '<html><head></head><body><div class="card"></div></body></html>', guardPolicy: { preset: 'strict', htmlMode: 'hybrid', allowedLocalRoots: ['D:/project/public/styles'], allowedRemoteImportOrigins: ['https://cdn.example.com'], }, sources: [ { sourceId: '/styles/docs.luis', source: '.card { color: #0f172a; }', }, ],})Practical Rule for rewrite
Section titled “Practical Rule for rewrite”rewrite accepts these values:
'auto''always''never'
Recommended default for daily use:
rewrite: 'auto'In practice:
- if a route does not need runtime, source
.luistags can be removed - generated CSS links stay in place
- routes that need runtime can keep source tags
sourceRoots Order Matters
Section titled “sourceRoots Order Matters”The order of sourceRoots matters.
Example:
sourceRoots: ['./public', './dist']This order is generally safer because it prevents old dist output from winning over live public sources.
Typical consequences of wrong order:
- your latest source change is invisible
- old
.luiscontent is resolved during dev - expected selectors do not appear in generated CSS
Runtime Options vs Hybrid Diagnostics
Section titled “Runtime Options vs Hybrid Diagnostics”These two fields use the same token parser, but they affect different places.
defaultRuntimeOptions: 'performance', // user-visible runtime behaviorhybridOptions: 'debug,performance', // terminal-visible hybrid diagnosticsdefaultRuntimeOptions is merged into every auto-discovered .luis source. The result goes into the generated manifest or payload and changes what the browser runtime may do.
hybridOptions is read by the hybrid build/dev process itself. It controls compile timing, warning, and rewrite-decision logs. It does not change generated runtime options.
Supported defaultRuntimeOptions tokens:
debug/!debugperformance/!performancemap/!maplazy/!lazyworker/!worker
For hybridOptions, the accepted shape is the same, but only these currently affect hybrid diagnostics:
performance: prints hybrid compile/evaluate timing logsdebug: prints hybrid compile warnings and rewrite-decision logs
Object form is also supported:
defaultRuntimeOptions: { performance: true, lazy: true, worker: 'auto',}General recommendation:
- user-facing runtime default:
defaultRuntimeOptions: 'performance' - build/dev diagnostics:
hybridOptions: 'debug,performance' - no defaults: omit the field or use
''
Source-level override example
Section titled “Source-level override example”defaultRuntimeOptions is applied to auto-discovered sources. A source-level data-luis can still override this default per source.
Config:
hybrid: { buildMode: 'initial', htmlOutputDir: './dist', sourceRoots: ['./public'], luisOutputDir: './dist/_hybrid', defaultRuntimeOptions: 'debug,performance',}HTML:
<link rel="stylesheet" href="/styles/docs.luis" data-luis="!debug,lazy">Effective runtime options for this source:
{ debug: false, performance: true, map: false, lazy: true, worker: 'auto',}