@salla.sa / twilight-theme-engine
Salla React主题背后的SDK它提供了店面路由、组件、钩子和API 客户端,以及主题组成的Vite插件-所以主题是一个小应用程序,而不是一个分支 店面。
建造的 TanStack开始,在边缘进行服务器渲染。
安装
你通常不会自己安装这个 salla theme create --type react 搭建一个主题
这已经取决于它了。
pnpm add @salla.sa/twilight-theme-engine
对等依赖被固定到 波浪字符范围 (~1.166.2 用于 @tanstack/*, vite ^8.1.5,
react ^19.2.4). 发动机的 dist 参考文献 @tanstack/react-start 内部,如此漂泊
在运行时被测试的次要程序之外破坏SSR。让安装程序警告你,而不是强迫你
决议。
里面有什么?
| 区域 | 它给了你什么 |
|---|---|
| 路线 | 现成的店面页面-产品,购物车,类别,博客, /account/*,…… |
| 组件 | 页眉/页脚、产品、购物车、主页块、模态/抽屉/下拉原语 |
| 钩子 | useStore, useTheme, useUser, useMoney, useAsset, useWishlist,…… |
| 注册表 | 按名称交换任何已注册的组件 |
| 钩槽 | 在定义的扩展点注入内容 |
| API | 用于Salla存储API的类型化客户端,用于SSR加载器 |
| i18n | react-i18next 整合,阿拉伯语/RTL优先 |
| 工具 | Vite插件(路由生成,虚拟模块),ESLint配置,SSR运行时 |
| 命令行界面 | twilight-check-manifest:列出主题中的错误 twilight.json |
文档
面向主题的指南驻留在 暮光之城网站 -从 开始跟踪 或者是 体系结构概述.
引擎内部深度潜水开始 docs/ 在这里:
| 文档 | 主题 |
|---|---|
| HOME_COMPONENTS.md | 家用组件系统和 data 支持合同 |
| usePageConfig.md | 统一页面配置 |
| useLocation.md | 位置和查询参数处理 |
| store-identity.md | 请求是针对哪个存储的,为什么不配置 |
| router-context.md | 跨SSR和CSR的请求范围上下文 |
| route-ids.md | 路由标识符 |
| route-pagination.md | 加载器中的分页 |
| ProductCard.md | 这个 ProductCard 合同 |
| gtm-integration.md | 谷歌标签管理器 |
| i18n-instance-lifecycle.md | 如何创建和共享i18n实例 |
| type-improvement-guide.md | 打字约定 |
子系统指出: src/api/README.md,
src/vite/README.md, tests/README.md.
使用
将引擎连接到主题中
两个文件可以做到这一点。 app/start.ts 安装请求中间件:
import { createStart } from '@tanstack/react-start';
import { twilightMiddleware, earlyHintsMiddleware } from '@salla.sa/twilight-theme-engine/tanstack';
export const startInstance = createStart(() => {
return {
requestMiddleware: [twilightMiddleware(), earlyHintsMiddleware()],
};
});
app/routes/__root.tsx 构建根路由并呈现提供程序:
import { TwilightProvider } from '@salla.sa/twilight-theme-engine';
import { createTwilightRootRoute } from '@salla.sa/twilight-theme-engine/tanstack';
import themeTranslations from 'virtual:twilight/theme-translations';
export const Route = createTwilightRootRoute()({ shellComponent: RootComponent });
<TwilightProvider> 接受捆绑 translations (加上可选的 debug, skeleton,
onReady, onError). 存储、区域设置和用户是 不 道具——中间件解决它们
每个请求。
组件注册表
import { registry, Component } from '@salla.sa/twilight-theme-engine';
registry.register('product:card', ProductCard);
registry.override('product:card', MyProductCard);
<Component name="product:card" product={product} />;
键是 结肠-分隔,引擎只能解析其中的三个: product:card,
home:* 块(通过 registerHomeComponents()), account:layout-pending。覆盖任何
其他名称是静默的no-op -其他所有内容都直接导入。
钩槽
import { defineHooks } from '@salla.sa/twilight-theme-engine/hooks/HookRegistry';
import { HookSlot } from '@salla.sa/twilight-theme-engine/hooks/HookSlot';
defineHooks({
'body:start': () => <AnnouncementBar />,
'product:form.end': ({ product }) => <TrustBadges product={product} />,
});
<HookSlot name="product:form.end" context={{ product }} />;
存储、主题和用户
import { useStore } from '@salla.sa/twilight-theme-engine/hooks/useStore';
import { useTheme } from '@salla.sa/twilight-theme-engine/hooks/useTheme';
import { useTwilight } from '@salla.sa/twilight-theme-engine';
function MyComponent() {
const store = useStore();
const { color, font, settings, isRTL } = useTheme();
const { user } = useTwilight();
const isDark = settings?.footer_is_dark ?? false;
}
设置是一个普通对象——用
?.和你自己的默认值。没有settings.get().
翻译
import { useTranslation } from '@salla.sa/twilight-theme-engine/i18n';
function MyComponent() {
const { t, locale, isRTL } = useTranslation();
return (
<>
<h1>{t('pages.cart.title')}</h1>
<p>{t('pages.products.sold_times', { count: 5 })}</p>
</>
);
}
useTranslation() 返回 react-i18next的 t, i18n, ready,加上区域信息
(locale, direction, isRTL, isLTR, languageName). 这个 /i18n 子路径也导出
I18nProvider, FALLBACK_LOCALE, SUPPORTED_LOCALES, RTL_LOCALES, isLocale,
getLanguageInfo.
金钱及资产
import { useMoney } from '@salla.sa/twilight-theme-engine/hooks/useMoney';
import { useAsset } from '@salla.sa/twilight-theme-engine/hooks/useAsset';
function ProductPrice({ product }) {
const { format } = useMoney(); // also: parse, isValid
const { cdn } = useAsset(); // also: asset, isPlaceholder
return (
<div>
<img src={cdn(product.image.url, 400)} alt="" loading="lazy" />
<p>{format(product.price)}</p>
</div>
);
}
format() 返回一个 ReactNode (不是字符串)——它将货币符号呈现为标记。
导入路径
引擎有~90个子路径导出。从最窄的包中导入,这样包就会很小:
// Core — provider, registry, context
import {
TwilightProvider,
useTwilight,
registry,
Component,
} from '@salla.sa/twilight-theme-engine';
// Hooks — one subpath each
import { useStore } from '@salla.sa/twilight-theme-engine/hooks/useStore';
import { useMoney } from '@salla.sa/twilight-theme-engine/hooks/useMoney';
// i18n
import { useTranslation, I18nProvider } from '@salla.sa/twilight-theme-engine/i18n';
// Components — grouped by domain
import { Link } from '@salla.sa/twilight-theme-engine/common';
import { Header, Footer } from '@salla.sa/twilight-theme-engine/layout';
import { CartItem, CartSummary } from '@salla.sa/twilight-theme-engine/cart';
import { ProductCard } from '@salla.sa/twilight-theme-engine/product';
// Routes
import { Home, DefaultHomeComponents } from '@salla.sa/twilight-theme-engine/routes/home';
// API clients — for loaders
import { store } from '@salla.sa/twilight-theme-engine/api/store';
// TanStack integration
import { createRouter, createTwilightRootRoute } from '@salla.sa/twilight-theme-engine/tanstack';
// Types
import type { Store, Theme, Product } from '@salla.sa/twilight-theme-engine/types';
权威列表是 exports 领域的 package.json。从来没有深刻含义
成 dist/ -这些路径不是公共API的一部分。
开发
从repo根目录:
pnpm --filter @salla.sa/twilight-theme-engine build # tsup + tsc + dts stubs
pnpm --filter @salla.sa/twilight-theme-engine test
pnpm --filter @salla.sa/twilight-theme-engine test:coverage
pnpm --filter @salla.sa/twilight-theme-engine typecheck
| 命令 | 描述 |
|---|---|
pnpm build | Bundle,添加JS扩展,emit声明和ambient .d.ts |
pnpm dev | tsup --watch |
pnpm test | 轻快地(test:watch, test:coverage, test:ci) |
pnpm typecheck | tsc --noEmit |
pnpm clean | 删除 dist/ |
主题消耗 dist/,所以 在运行或类型检查主题之前构建引擎。
添加新的公共导出意味着添加子路径 exports ——否则消费者就不能
达到它。通过安装独立的Tania来验证更改的发布是否有效
(为什么)。
测试惯例,包括ssr -vs-浏览器的划分 tests/README.md.
许可证
麻省理工学院