REACT_THEME_TYPE & manifest helpers
Node helpers that check twilight.json declares "type": "react", the line that tells the Salla CLI this is a React theme.
import { REACT_THEME_TYPE, getThemeType, isReactThemeManifest, describeThemeTypeIssue, TwilightManifest } from '@salla.sa/twilight-theme-engine/vite';In plain words
Every theme has a twilight.json file describing it. Older themes built with Twig templates and React themes share that format, so a React theme marks itself with one line: "type": "react". The Salla CLI reads it to decide how to run and publish your theme; without it the folder is treated as a Twig theme.
These helpers check that line from your own scripts, for example a CI step that fails when the manifest is wrong. They take the manifest already parsed with JSON.parse, and they run in Node: import them in build scripts, never in a page.
Signature
const REACT_THEME_TYPE = 'react';
function getThemeType(raw: unknown): string | undefined
function isReactThemeManifest(raw: unknown): boolean
function describeThemeTypeIssue(raw: unknown, fileLabel?: string): string | null // fileLabel: 'twilight.json'
interface TwilightManifest {
type?: string;
name?: Record<string, string>;
description?: Record<string, string>;
repository?: string;
author_email?: string;
support_url?: string;
features?: string[];
settings?: unknown[];
components?: unknown[];
}
// Input getThemeType isReactThemeManifest describeThemeTypeIssue
// { type: 'react' } 'react' true null
// {} null { type: 42 } { type: ' ' }
// undefined false 'twilight.json has no "type": "react" — …'
// { type: ' react ' } ' react ' false '… compares this value exactly …'
// { type: 'React' } 'React' false '… declares "type": "React", but …'Example
// Run from the theme folder in CI: node scripts/check-manifest.mjs
import { readFileSync } from 'node:fs';
import { describeThemeTypeIssue } from '@salla.sa/twilight-theme-engine/vite';
const manifest = JSON.parse(readFileSync('twilight.json', 'utf8'));
const issue = describeThemeTypeIssue(manifest);
if (issue) {
console.error(issue);
process.exit(1);
}
console.log('twilight.json declares a React theme.');
How it behaves
getThemeTypereturnstypeexactly as written, orundefinedwhen the input is not an object ortypeis missing, not a string, or only whitespace. It never trims, because the CLI compares with===.isReactThemeManifest(raw)isgetThemeType(raw) === REACT_THEME_TYPE, so'React'and' react 'are false.describeThemeTypeIssuereturnsnullfor a correct manifest, otherwise one sentence naming the problem and the fix: notype, areactwrapped in whitespace (quoted withJSON.stringifyso the spaces show), or another value.fileLabelis the file name used in the sentence.The engine runs the same check in
vite dev: thetwilight:schemaplugin prints[twilight-react:schema] <message>when the dev server starts and whenevertwilight.jsonchanges. A build does not check.Absence means Twig: a
"twig"value is never written.TwilightManifesttypes only the top level;settingsandcomponentsareunknown[].
Gotchas
Import them only in Node.
@salla.sa/twilight-theme-engine/viteloadsfs,path,crypto,module,esbuildand the nativeoxc-parserat the top of the module, so importing it from a component breaks the browser bundle and the server build. That is also why this page has no live demo."type": "React"or" react "looks right and still sends the theme down the Twig path in the CLI. The dev server warns about both; a build does not.A missing
twilight.jsonis silent invite dev: only a present, wrong one warns. Invalid JSON gets its own warning (… is not valid JSON — theme settings and the dev widget will be empty.), because these helpers receive parsed input.
Related
The one Vite plugin call in a theme's vite.config.ts: server rendering, a route for every storefront page, translations and build checks.
DevSettingsWidgetA development-only floating panel that lists your twilight.json settings and home-component fields with defaults, and previews edited values in vite dev.